• 硬核,20道经典Java基础面试题


    最近整理了20道Java基础面试题,大家一起加油哈

    1. ArrayList和LinkedList有什么区别?

    可以从它们的底层数据结构、效率、开销进行阐述哈

    • ArrayList是数组的数据结构,LinkedList是链表的数据结构。

    • 随机访问的时候,ArrayList的效率比较高,因为LinkedList要移动指针,而ArrayList是基于索引(index)的数据结构,可以直接映射到。

    • 插入、删除数据时,LinkedList的效率比较高,因为ArrayList要移动数据。

    • LinkedList比ArrayList开销更大,因为LinkedList的节点除了存储数据,还需要存储引用。

    2. final, finally, finalize的区别

    • final用于声明属性,方法和类, 分别表示属性不可变, 方法不可覆盖, 类不可继承.

    • finally是异常处理语句结构的一部分,表示总是执行.

    • finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等. JVM不保证此方法总被调用.

    3. 重写和重载的区别

    • 作用范围:重写的作用范围是父类和子类之间;重载是发生在一个类里面

    • 参数列表:重载必须不同;重写不能修改

    • 返回类型:重载可修改;重写方法返回相同类型或子类

    • 抛出异常:重载可修改;重写可减少或删除,一定不能抛出新的或者更广的异常

    • 访问权限:重载可修改;重写一定不能做更严格的限制

    4. Java 8的接口新增了哪些特性?

    JDK8 的新特性

    • lambada表达式

    • 函数式接口

    • 方法引用

    • 默认方法

    • Stream API

    • Optional

    • Date Time API(如LocalDate)

    • 重复注解

    • Base64

    • JVM的新特性(如元空间Metaspace代替持久代)

    5. 两个对象的hashCode()相同,则 equals()是否也一定为 true?

    两个对象equals相等,则它们的hashcode必须相等,如果两个对象的hashCode()相同,则equals()不一定为true。

    hashCode 的常规协定:

    在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。

    两个对象的equals()相等,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。

    两个对象的equals()不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不要求一定生成不同的整数结果。但是,为不相等的对象生成不同整数结果可以提高哈希表的性能。

    6. 抽象类和接口有什么区别

    • 抽象类要被子类继承,接口要被子类实现。

    • 抽象类可以有构造方法,接口中不能有构造方法。

    • 抽象类中可以有普通成员变量,接口中没有普通成员变量,它的变量只能是公共的静态的常量

    • 一个类可以实现多个接口,但是只能继承一个父类,这个父类可以是抽象类。

    • 接口只能做方法声明,抽象类中可以作方法声明,也可以做方法实现。

    • 抽象级别(从高到低):接口>抽象类>实现类。

    • 抽象类主要是用来抽象类别,接口主要是用来抽象方法功能。

    • 抽象类的关键字是abstract,接口的关键字是interface

    7.  BIO、NIO、AIO 有什么区别?

    BIO是同步并阻塞的,NIO是同步非阻塞,AIO是异步非阻塞。

    • BIO:线程发起 IO 请求,不管内核是否准备好 IO 操作,从发起请求起,线程一直阻塞,直到操作完成。

    • NIO:线程发起 IO 请求,立即返回;内核在做好 IO 操作的准备之后,通过调用注册的回调函数通知线程做 IO 操作,线程开始阻塞,直到操作完成。

    • AIO:线程发起 IO 请求,立即返回;内存做好 IO 操作的准备之后,做 IO 操作,直到操作完成或者失败,通过调用注册的回调函数通知线程做 IO 操作完成或者失败。

    BIO 是一个连接一个线程。,NIO 是一个请求一个线程。,AIO 是一个有效请求一个线程。

    • BIO:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。

    • NIO:同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。

    • AIO:异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的 IO 请求都是由 OS 先完成了再通知服务器应用去启动线程进行处理。

    8. String,Stringbuffer,StringBuilder的区别

    String:

    • String类是一个不可变的类,一旦创建就不可以修改。

    • String是final类,不能被继承

    • String实现了equals()方法和hashCode()方法

    StringBuffer:

    • 继承自AbstractStringBuilder,是可变类。

    • StringBuffer是线程安全的

    • 可以通过append方法动态构造数据。

    StringBuilder:

    • 继承自AbstractStringBuilder,是可变类。

    • StringBuilder是非线性安全的。

    • 执行效率比StringBuffer高。

    9. 静态代理和动态代理的区别

    静态代理中代理类在编译期就已经确定,而动态代理则是JVM运行时动态生成,静态代理的效 率相对动态代理来说相对高一些,但是静态代理代码冗余大,一单需要修改接口,代理类和委 托类都需要修改。

    10. JAVA中的几种基本数据类型是什么,各自占用多少字节呢

    基本类型位数字节
    int324
    short162
    long648
    byte81
    char162
    float324
    double648
    boolean

    对于boolean,官方文档未明确定义,它依赖于 JVM 厂商的具体实现。逻辑上理解是占用 1位,但是实际中会考虑计算机高效存储因素

    感兴趣的小伙伴,可以去看官网

    11. Comparator与Comparable有什么区别?

    • Comparable & Comparator 都是用来实现集合中元素的比较、排序的,只是 Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。

    • Comparator位于包java.util下,而Comparable位于包 java.lang下。

    • Comparable 是一个对象本身就已经支持自比较所需要实现的接口(如 String、Integer 自己就可以完成比较大小操作,已经实现了Comparable接口) 自定义的类要在加入list容器中后能够排序,可以实现Comparable接口,在用Collections类的sort方法排序时,如果不指定Comparator,那么就以自然顺序排序, 这里的自然顺序就是实现Comparable接口设定的排序方式。

    • 而 Comparator 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。

    • 可以说一个是自已完成比较,一个是外部程序实现比较的差别而已。用 Comparator 是策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为。比如:你想对整数采用绝对值大小来排序,Integer 是不符合要求的,你不需要去修改 Integer 类(实际上你也不能这么做)去改变它的排序行为,只要使用一个实现了 Comparator 接口的对象来实现控制它的排序就行了。

    12. JDK动态代理和CGLIB动态代理的区别

    • JDK动态代理只能对实现了接口的类生成代理,而不能针对类。

    • CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承, 所以该类或方法最好不要声明成final。

    13. String类能被继承吗,为什么。

    首先,String是一个final修饰的类,final修饰的类不可以被继承。

    1. public final class String
    2.     implements java.io.SerializableComparable<String>, CharSequence {

    String类为什么不能被继承呢?

    有两个原因:

    • 效率性,String 类作为最常用的类之一,禁止被继承和重写,可以提高效率。

    • 安全性,String 类中有很多调用底层的本地方法,调用了操作系统的 API,如果方法可以重写,可能被植入恶意代码,破坏程序。

    14.说说Java中多态的实现原理

    • 多态机制包括静态多态(编译时多态)和动态多态(运行时多态)

    • 静态多态比如说重载,动态多态一般指在运行时才能确定调用哪个方法。

    • 我们通常所说的多态一般指运行时多态,也就是编译时不确定究竟调用哪个具体方法,一直等到运行时才能确定。

    • 多态实现方式:子类继承父类(extends)和类实现接口(implements)

    • 多态核心之处就在于对父类方法的改写或对接口方法的实现,以取得在运行时不同的执行效果。

    • Java 里对象方法的调用是依靠类信息里的方法表实现的,对象方法引用调用和接口方法引用调用的大致思想是一样的。当调用对象的某个方法时,JVM查找该对象类的方法表以确定该方法的直接引用地址,有了地址后才真正调用该方法。

    举个例子吧,假设有个Fruit父类,一个taste味道方法,两个子类Apple和Pear,如下:

    1. abstract class Fruit {
    2.     abstract String taste() ;
    3. }
    4. class Apple extends Fruit {
    5.     @Override
    6.     String taste() {
    7.         return "酸酸的";
    8.     }
    9. }
    10. class Pear extends Fruit {
    11.     @Override
    12.     String taste() {
    13.         return "甜甜的";
    14.     }
    15. }
    16. public class Test {
    17.     public static void main(String[] args) {
    18.         Fruit f = new Apple();
    19.         System.out.println(f.taste());
    20.     }
    21. }

    程序运行,当调用对象Fruit f的方法taste时,JVM查找Fruit对象类的方法表以确定taste方法的直接引用地址,到底来自Apple还是Pear,确定后才真正调用对应子类的taste方法,

    15. 说下面向对象四大特性

    封装、继承、多态、抽象。

    16. int和Integer有什么区别,还有Integer缓存的实现

    这里考察3个知识点吧:

    • int 是基本数据类型,interger 是 int 的封装类

    • int 默认值为 0 ,而interger 默认值为 null, Interger使用需要判空处理

    • Integer的缓存机制:为了节省内存和提高性能,Integer类在内部通过使用相同的对象引用实现缓存和重用,Integer类默认在-128 ~ 127 之间,可以通过 -XX:AutoBoxCacheMax进行修改,且这种机制仅在自动装箱的时候有用,在使用构造器创建Integer对象时无用。

    看个Integer的缓存的例子,加深一下印象哈:

    1. Integer a = 10;
    2. Integer b = 10;
    3. Integer c = 129;
    4. Integer d = 129;
    5. System.out.println(a == b);
    6. System.out.println(c == d);
    7. 输出结果:
    8. true
    9. false

    17. 说说反射的用途及实现原理,Java获取反射的三种方法

    这道面试题,看我这篇文章哈:谈谈Java反射:从入门到实践,再到原理

    Java获取反射的三种方法

    • 第一种,使用 Class.forName 静态方法。

    • 第二种,使用类的.class 方法

    • 第三种,使用实例对象的 getClass() 方法。

    18. &和&&的区别

    • 按位与, a&b 表示把a和b都转换成二进制数,再进行与的运算;

    • &和&&都是逻辑运算符号,&&又叫短路运算符

    • 逻辑与,a&& b ,a&b 都表示当且仅当两个操作数均为 true时,其结果才为 true,否则为false。

    • 逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true,整个表达式的值才是true。但是,&&之所以称为短路运算,是因为如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算。

    19. Java中IO流分为几种?

    • Java中的流分为两种:一种是字节流,另一种是字符流。

    • IO流分别由四个抽象类来表示(两输入两输出):InputStream,OutputStream,Reader,Writer。

    20.Java有哪些数据类型

    定义:Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分 配了不同大小的内存空间。

    基本数据类型

    • 数值型

    • 整数类型(byte,short,int,long)

    • 浮点类型(float,double)

    • 字符型(char)

    • 布尔型(boolean)

    引用数据类型

    • 类(class)

    • 接口(interface)

    • 数组([])

  • 相关阅读:
    使用nmea+pps为激光雷达做授时,然后使用gtimu协议中的周和周内秒计算imu数据的时间戳,结果相差一秒,同样来自gps时间,到底imu和雷达的时间戳哪个是对的呢
    《MATLAB科研绘图与学术图表绘制从入门到精通》示例:绘制婴儿性别比例饼图
    计算机毕业设计ssm社区疫情防控系统3j56g系统+程序+源码+lw+远程部署
    Github项目徽标
    阿斯达年代记下载注册+短信验证教程分享
    虚拟机安装k8s(1.20.2版本)集群,从0-1
    二十一、java版 SpringCloud分布式微服务云架构之Java 继承
    Mybatis快速入门
    static详解
    I2C总线与E²PROM
  • 原文地址:https://blog.csdn.net/weixin_70730532/article/details/125891927