Java 面试题集绵
一、Java基础
问题1:JDK 、JRE和JVM的关系?
答:A. JDK(Java Development Kit)即Java开发工具包,包含编写Java程序所必须的编译、运行等开发工具以及JRE,开发工具如:用于编译java程序的javac命令、用于启动JVM运行java程序的java命令、用于生成文档的javadoc命令以及用于打包的jar命令等;
B. JRE(Java Runtime Environment)即Java运行环境,提供了运行Java应用程序所必须的软件环境,包含有Java虚拟机(JVM)和丰富的系统类库,系统类库即为java提前封装好的功能类,只需拿来直接使用即可,可以大大的提高开发效率;
C. JVM(Java Virtual Machines)即Java虚拟机,提供了字节码文件(.class)的运行环境支持;
D. 即JDK包含JRE,JRE包含JVM。
问题2:==和equals的区别是什么?
答:A. ==:对于基本类型来说是比较值是否相等,对于引用类型来说是比较两个变量是否引用同一个对象;
B. equals:默认情况下是引用比较是否相等,只是很多类重新了equals方法,比如String、Integer等把它变成了值比较,所以一般情况下equals比较的是值是否相等。
问题3:Java支持的数据类型及什么是自动拆装箱?
答:A. 八大基本数据类型:整数值型——byte、short、int、long,字符型——char ,浮点类型——float、double ,布尔型——boolean;
B. 整数默认int型,小数默认是double型,float和long类型的必须加后缀F和L;
C. String是引用类型不是基本类型,引用类型声明的变量是指该变量在内存中实际存储的是一个引用地址,实体在堆中,引用类型包括类、接口、数组等,String类还是final修饰的;
D. 包装类属于引用类型,自动装箱和拆箱就是基本类型和引用类型之间的转换,至于为什么要转换,因为基本类型转换为引用类型后,就可以new对象,从而调用包装类中封装好的方法,进行基本类型之间的转换或者toString(当然用类名直接调用也可以,便于一眼看出该方法是静态的),还有就是如果集合中想存放基本类型,泛型的限定类型只能是对应的包装类型。
问题4:String str = "i"与String str = new String("i")一样吗?
答:A. String str = "i"的方式,虚拟机会将其分配到常量池中;
B. String str = new String("i") 则会被分到堆内存中。
问题5:String、StringBuilder、StringBuffer和StringJoiner的区别?
答:A. 相同点:可以储存和操作字符串;
B. 不同点:常量String是只读字符串,它引用的字符串内容是不能被改变的;
变量StringBuffer和StringBuilder类表示的字符串对象可以直接进行修改;
StringBuffer是线程安全,而StringBuilder是线程不安全的,故效率较高些;
StringJoiner由Java8提供,构造由分隔符分隔的字符序列,是通过StringBuilder实现的。
问题6:访问控制修饰符的权限?
答:A. private:修饰的类成员,只能被该类自身的方法访问和修改;
B. 默认:没有访问控制符,修饰的类或类成员,只能被该类自身和与它在同一个包中的其他类访问和引用;
C. protected:修饰的类成员,可以被该类自身、与它在同一个包中的其他类以及在其他包中的该类的子类访问和引用;
D. public:修饰的类或类成员,可以被所有的类访问和引用,注意Java程序的主类都必须是public类。
问题7:VO/DTO/DO/PO对象类型区别?
答:A. VO(View Object):视图对象,是前端对应界面显示的数据对象,只包含前端展示的数据,因为这是出于减少传输数据量大小和保护数据库结构不外泄的考虑;
B. DTO(Data Transfer Object):数据传输对象,DTO用于“上层”调用接口时传输,通常用于不同服务或服务不同分层之间的数据传输;
C. DO(Domain Object):领域对象,就是从现实世界中抽象出来的有形或无形的业务实体;
D. PO(Persistent Object):持久化对象,它跟持久层(如关系型数据库)的数据结构形成一一对应的映射关系,数据表中的每个字段就对应PO的一个属性;
E. 这些POJO(包括VO/DTO/DO/PO)对象命名需大写。
问题8:wait(等待)和sleep(休眠)的区别?
答:A. 方法附属:wait是Object类的方法,而sleep是Thread类的静态方法;
B. 作用域:wait只能用在同步方法或同步代码块中,而sleep可以用在任何地方;
C. 释放锁:wait会释放锁,而sleep不会释放锁;
D. 异常:wait不需要捕获异常,而sleep必须捕获InterruptedException异常;
E. 使用:wait要使用notify()/notifyAll()直接唤醒,而sleep时间到会自动恢复;
F. 应用场景:wait多用于多线程之间的通信,而sleep一般用于当前线程休眠或者轮循暂停操作;
G. 线程切换:sleep会让出CPU执行时间且强制上下文切换,而wait则不一定,wait后可能还是有机会重新竞争到锁继续执行的。
问题9:接口和抽象类的区别?
答:A. 实现:抽象类使用extends来继承,接口使用implements来实现;
B. 构造函数:抽象类可以有构造函数,接口不能有;
C. 数量:类可以实现很多个接口,但是只能继承一个抽象类;
D. 访问修饰符:接口中的方法默认使用public修饰,抽象类中的普通方法可以是任意访问修饰符,而抽象方法是非private修饰符。
问题10:throw和throws关键字的区别?
答:A. throw:用来抛出任意异常的,包括自定义的异常类对象,throw可以中断程序运行,因此可以用来代替return;
B. throws:总是出现在一个方法名上,用来声明该方法可能抛出的各种异常,如果方法抛出了异常,那么调用这个方法的时候就需要处理这个异常。
问题11:final、finally和finalize关键字的区别?
答:A. final:用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承,内部类要访问局部变量,局部变量必须定义成final类型;
B. finally:是异常处理语句结构的一部分,表示总是执行,可以省略;
C. finalize:是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收。
二、多线程
问题1:创建线程的方式
答:A. 继承Thread类,重写run方法;
B. 实现Runnable接口,实现run方法;
C. 实现Callable<返回值类型>接口,实现call方法,有返回值;
D. 通过线程池(Executor接口),创建线程(固定大小FixThreadPool、单线程SingleThreadExecutor、缓存CachedThreadPool线程池),但是这些会产生OOM问题, 阿里巴巴推荐使用newThreadPool()创建线程池;
E. 匿名内部类的方式;
F. Spring中@Async注解。
可参考:Java创建多线程的8种方式
问题2:多线程中synchronized锁升级的原理是什么?
答:A. 升级原理:在锁对象的对象头里面有一个线程ID字段,在第一次访问的时候线程ID为空,JVM让其持有偏向锁,并将线程ID设置为其线程ID,再次进入的时候会先判断线程ID是否与其线程ID一致,如果一致则可以直接使用此对象,如果不一致,则升级偏向锁为轻量级锁,通过自旋循环一定次数来获取锁,执行一定次数之后,如果还没有正常获取到要使用的对象,此时就会把锁从轻量级升级为重量级锁,此过程就构成了synchronized锁的升级;
B. 升级目的:锁升级是为了减低了锁带来的性能消耗,在Java 6之后优化synchronized的实现方式,使用了偏向锁升级为轻量级锁再升级到重量级锁的方式,从而减低了锁带来的性能消耗。
三、集合类
问题1:ArrayList和LinkedList的区别?
答:A. 数据结构:ArrayList是基于动态数组的,LinkedList是基于双向链表的;
B. 随机访问:ArrayList的get()和set(),性能要优于LinkedList,而add()和remove(),性能不一定慢于LinkedList;
C. 增加和删除:LinkedList不一定慢于ArrayList。
问题2:迭代器Iterator是什么及特点?
答:A. Iterator接口提供了很多对集合元素进行迭代的方法,每一个集合类都包含了可以返回迭代器实例的迭代方法;
B. 迭代器可以在迭代的过程中删除底层集合的元素,但是不可以直接调用集合的remove()删除,可以通过迭代器的remove()方法删除;
C. Iterator特点是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出ConcurrentModificationException异常。
问题3:怎么确保一个集合不能被修改?
答:A. 使用Collections包下面的unmodifiableXXX方法创建只读集合,对于操作返回值,改变集合的任何操作报 java.lang.UnsupportedOperationException异常;
B. 不能使用final,因为final修饰的引用类型,只是引用地址不可变,并不是引用所指向的对象内容不可变;
四、JVM
问题1:Java引用类型分类?
答:A. 强引用:关联的对象不会被回收,例如使用new关键字新建对象;
B. 软引用:关联的对象只有在内存不够的情况下才会被回收,使用SoftReference类来新建软引用;
C. 弱引用:关联的对象一定被回收,使用WeakReference类来实现弱引用;
D. 虚引用:唯一目的是能在这个对象被回收时收到一个系统通知,使用PhantomReference类来实现虚引用。
问题2:哪些场景会产生OOM?
答:A. 堆内存溢出;
B. 方法区(运行时常量池)和元空间溢出;
C. 直接内存溢出;
D. 栈内存溢出。
可参考:哪些场景会产生OOM及解决方式
可参考:Java面试问题200+