admin管理员组

文章数量:1530869

2024年4月6日发(作者:)

Java面试题及答案整理

Java 最常见的面试题的答案已经全部更新完了,有些答案是自己总结

的,也有些答案是在网上搜集整理的。这些答案难免会存在一些错误,

仅供大家参考。如果发现错误还望大家多多包涵,不吝赐教,谢谢~

如果不背 Java 面试题的答案,肯定面试会挂!

这套Java面试题大全,希望对大家有帮助哈~

博主已将以下这些面试题整理成了一个Java面试手册,是PDF版的

Java

1、 java常见2021年最新面试题附答案解析

2、 java常见面试题及答案汇总2021年最新版

3、 java常见面试题2021年及答案汇总

4、 java最新2021年面试题及答案汇总版

5、 java最新2021年面试题大汇总附答案

6、 java最新2021年面试题附答案解析大汇总

7、 java最新2021年面试题高级面试题及附答案解析

8、 java最新基础面试题及答案整理

9、 java最新面试题2021年常见面试题及答案汇总

10、 java最新面试题及答案整理汇总版

11、 java最新面试题及答案附答案汇总

12、 java最新面试题2021年面试题及答案汇总

13、 java最新面试题常见面试题及答案汇总

14、 java面试2021秋招面试问题附答案

15、 java面试题及答案整理汇总2021年最新版

16、 java面试题及答案整理2021年最新汇总版

17、 java面试题大全带答案持续更新

18、 java面试题大汇总2021年附答案解析

19、 java面试题大汇总2021面试题及答案汇总

20、 java面试题目大汇总附参考答案

21、 java高级面试题及答案2021版

22、 java高级面试题及答案企业真面试题

23、 java高级面试题及答案最新版

24、 java高级面试题合集附答案解析

25、 java高级面试题整理及答案

26、 java高级面试题中级面试题大汇总

1、抽象工厂模式和原型模式之间的区别?

抽象工厂模式:通常由工厂方法模式来实现。但一个工厂中往往含有多

个工厂方法生成一系列的产品。这个模式强调的是客户代码一次保证只

使用一个系列的产品。当要切换为另一个系列的产品,换一个工厂类即

可。

原型模式:工厂方法的最大缺点就是,对应一个继承体系的产品类,要

有一个同样复杂的工厂类的继承体系。我们可以把工厂类中的工厂方法

放到产品类自身之中吗?如果这样的话,就可以将两个继承体系为一个。

这也就是原型模式的思想,原型模式中的工厂方法为clone,它会返回

一个拷贝(可以是浅拷贝,也可以是深拷贝,由设计者决定)。为了保

证用户代码中到时可以通过指针调用clone来动态绑定地生成所需的

具体的类。这些原型对象必须事先构造好。

原型模式想对工厂方法模式的另一个好处是,拷贝的效率一般对构造的

效率要高。

2、在 Java 程序中怎么保证多线程的运行安全?

出现线程安全问题的原因一般都是三个原因:

1、 线程切换带来的原子性问题 解决办法:使用多线程之间同步

synchronized或使用锁(lock)。

2、 缓存导致的可见性问题 解决办法:synchronized、volatile、LOCK,

可以解决可见性问题

3、 编译优化带来的有序性问题 解决办法:Happens-Before 规则可

以解决有序性问题

3、volatile 修饰符的有过什么实践?

一种实践是用 volatile 修饰 long 和 double 变量,使其能按原子类

型来读写。double 和 long 都是64位宽,因此对这两种类型的读是

分为两部分的,第一次读取第一个 32 位,然后再读剩下的 32 位,

这个过程不是原子的,但 Java 中 volatile 型的 long 或 double 变

量的读写是原子的。volatile 修复符的另一个作用是提供内存屏障

(memory barrier),例如在分布式框架中的应用。简单的说,就是

当你写一个 volatile 变量之前,Java 内存模型会插入一个写屏障

(write barrier),读一个 volatile 变量之前,会插入一个读屏障(read

barrier)。意思就是说,在你写一个 volatile 域时,能保证任何线程

都能看到你写的值,同时,在写之前,也能保证任何数值的更新对所有

线程是可见的,因为内存屏障会将其他所有写的值更新到缓存。

4、Java中各种数据默认值

1、 Byte,short,int,long默认是都是0

2、 Boolean默认值是false

3、 Char类型的默认值是’’

4、 Float与double类型的默认是0.0

5、 对象类型的默认值是null

5、说说Java 垃圾回收机制

在 Java 中,程序员是不需要显示的去释放一个对象的内存的,而是由

虚拟机自行执行。在 JVM 中,有一个垃圾回收线程,它是低优先级的,

在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,

才会触发执行,扫面那些没有被任何引用的对象,并将它们添加到要回

收的集合中,进行回收。

6、有没有可能两个不相等的对象有有相同的 hashcode?

有可能,两个不相等的对象可能会有相同的 hashcode 值,这就是为

什么在 hashmap 中会有冲突。相等 hashcode 值的规定只是说如果

两个对象相等,必须有相同的hashcode 值,但是没有关于不相等对

象的任何规定。

7、synchronized 和 Lock 有什么区别?

1、 首先synchronized是Java内置关键字,在JVM层面,Lock是个

Java类;

2、 synchronized 可以给类、方法、代码块加锁;而 lock 只能给代

码块加锁。

3、 synchronized 不需要手动获取锁和释放锁,使用简单,发生异常

会自动释放锁,不会造成死锁;而 lock 需要自己加锁和释放锁,如果

使用不当没有 unLock()去释放锁就会造成死锁。

4、 通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无

法办到。

8、什么是Vector

Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程

的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写

而引起的不一致性,但实现同步需要很高的花费,访问它比访问

ArrayList慢很多

ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对

元素进行快速随机访问。当从ArrayList的中间位置插入或者删除元素

时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找

和遍历,不适合插入和删除。ArrayList的缺点是每个元素之间不能有

间隔。

9、对象的访问定位有哪几种方式?

建立对象就是为了使用对象,我们的Java程序通过栈上的 reference

数据来操作堆上的具体对象。对象的访问方式有虚拟机实现而定,目前

主流的访问方式有使用句柄和直接指针2种:

句柄:如果使用句柄的话,那么Java堆中将会划分出一块内存来作为

句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对

象实例数据与类型数据各自的具体地址信息。

直接指针:如果使用直接指针访问,那么 Java 堆对象的布局中就必须

考虑如何放置访问类型数据的相关信息,而reference 中存储的直接就

是对象的地址。

这两种对象访问方式各有优势。使用句柄来访问的最大好处是

reference 中存储的是稳定的句柄地址,在对象被移动时只会改变句柄

中的实例数据指针,而 reference 本身不需要修改。使用直接指针访

问方式最大的好处就是速度快,它节省了一次指针定位的时间开销。

10、equals 和 == 的区别?#

通俗点讲:是看看左右是不是一个东西。equals是看看左右是不是长

得一样。如何记住嘛。如果单纯是想记住,:等于。equals:相同。两

个长得一样的人,只能说长的相同(equals),但是不等于他们俩是一个

人。你只要记住equals,==就不用记了。

术语来讲的区别:

1、 ==是判断两个变量或实例是不是指向同一个内存空间 equals是判

断两个变量或实例所指向的内存空间的值是不是相同

2、 ==是指对内存地址进行比较 equals()是对字符串的内容进行比较

3.==指引用是否相同 equals()指的是值是否相同

11、Parallel Old 收集器(多线程标记整理算法)

Parallel Old 收集器是Parallel Scavenge的年老代版本,使用多线程

的标记-整理算法,在 JDK1.6才开始提供。

在 JDK1.6 之前,新生代使用 ParallelScavenge 收集器只能搭配年老

代的 Serial Old 收集器,只能保证新生代的吞吐量优先,无法保证整

体的吞吐量, Parallel Old 正是为了在年老代同样提供吞吐量优先的

垃圾收集器, 如果系统对吞吐量要求比较高,可以优先考虑新生代

Parallel Scavenge和年老代 Parallel Old 收集器的搭配策略。

12、对象分配内存是否线程安全?

对象创建十分频繁,即使修改一个指针的位置在并发下也不是线程安全

的,可能正给对象 A 分配内存,指针还没来得及修改,对象 B 又使

用了指针来分配内存。

解决方法:① CAS 加失败重试保证更新原子性。② 把内存分配按线

程划分在不同空间,即每个线程在 Java 堆中预先分配一小块内存,叫

做本地线程分配缓冲 TLAB,哪个线程要分配内存就在对应的 TLAB

分配,TLAB 用完了再进行同步。

13、当一个线程进入某个对象的一个synchronized的实例方法后,其它线程是否

可进入此对象的其它方法?

如果其他方法没有synchronized的话,其他线程是可以进入的。

所以要开放一个线程安全的对象时,得保证每个方法都是线程安全的。

14、Serial 与 Parallel GC 之间的不同之处?

Serial 与 Parallel 在 GC 执行的时候都会引起 stop-the-world。它

们之间主要不同 serial 收集器是默认的复制收集器,执行 GC 的时候

只有一个线程,而parallel 收集器使用多个 GC 线程来执行。

15、为什么线程通信的方法 wait(), notify()和 notifyAll()被定义在 Object 类

里?

因为Java所有类的都继承了Object,Java想让任何对象都可以作为锁,

并且 wait(),notify()等方法用于等待对象的锁或者唤醒线程,在 Java

的线程中并没有可供任何对象使用的锁,所以任意对象调用方法一定定

义在Object类中。

有的人会说,既然是线程放弃对象锁,那也可以把wait()定义在Thread

类里面啊,新定义的线程继承于Thread类,也不需要重新定义wait()

方法的实现。然而,这样做有一个非常大的问题,一个线程完全可以持

有很多锁,你一个线程放弃锁的时候,到底要放弃哪个锁?当然了,这

种设计并不是不能实现,只是管理起来更加复杂。

16、redux异步中间件之间的优劣?

redux-thunk优点:

1、 体积小: redux-thunk的实现方式很简单,只有不到20行代码

2、 使用简单: redux-thunk没有引入像redux-saga或者

redux-observable额外的范式,上手简单

redux-thunk缺陷:

1、 样板代码过多: 与redux本身一样,通常一个请求需要大量的代码,

而且很多都是重复性质的

2、 耦合严重: 异步操作与redux的action偶合在一起,不方便管理

3、 功能孱弱: 有一些实际开发中常用的功能需要自己进行封装

redux-saga优点:

1、 异步解耦: 异步操作被被转移到单独 中,不再是掺杂在

或 中

2、 action摆脱thunk function: dispatch 的参数依然是一个纯粹的

action (FSA),而不是充满 “黑魔法” thunk function

3、 异常处理: 受益于 generator function 的 saga 实现,代码异常

/请求失败 都可以直接通过 try/catch 语法直接捕获处理

4、 功能强大: redux-saga提供了大量的Saga 辅助函数和Effect 创

建器供开发者使用,开发者无须封装或者简单封装即可使用

5、 灵活: redux-saga可以将多个Saga可以串行/并行组合起来,形成

一个非常实用的异步flow

6、 易测试,提供了各种case的测试方案,包括mock task,分支覆

盖等等

redux-saga缺陷:

1、 额外的学习成本: redux-saga不仅在使用难以理解的 generator

function,而且有数十个API,学习成本远超redux-thunk,最重要的是你

的额外学习成本是只服务于这个库的,与redux-observable不

同,redux-observable虽然也有额外学习成本但是背后是rxjs和一整套

思想

2、 体积庞大: 体积略大,代码近2000行,min版25KB左右

3、 功能过剩: 实际上并发控制等功能很难用到,但是我们依然需要引入

这些代码

4、 ts支持不友好: yield无法返回TS类型

redux-observable优点:

1、 功能最强: 由于背靠rxjs这个强大的响应式编程的库,借助rxjs的操

作符,你可以几乎做任何你能想到的异步处理

2、 背靠rxjs: 由于有rxjs的加持,如果你已经学习了

rxjs,redux-observable的学习成本并不高,而且随着rxjs的升级

redux-observable也会变得更强大

redux-observable缺陷:

1、 学习成本奇高: 如果你不会rxjs,则需要额外学习两个复杂的库

2、 社区一般: redux-observable的下载量只有redux-saga的1/5,

社区也不够活跃,在复杂异步流中间件这个层面redux-saga仍处于领

导地位

关于redux-saga与redux-observable的详细比较可见此链接

最近在备战面试的过程中,整理一下面试题。大多数题目都是自己手敲

的,网上也有很多这样的总结。自己感觉总是很乱,所以花了很久把自

己觉得重要的东西总结了一下。

17、类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式?

双亲委托模型的重要用途是为了解决类载入过程中的安全性问题。

1、 假设有一个开发者自己编写了一个名为

的类,想借此

欺骗JVM。现在他要使用自定义

ClassLoader

来加载自己编写的

类。

2、 然而幸运的是,双亲委托模型不会让他成功。因为JVM会优先在

Bootstrap ClassLoader

的路径下找到

类,并载入它

Java的类加载是否一定遵循双亲委托模型?

1、 在实际开发中,我们可以通过自定义ClassLoader,并重写父类的

loadClass方法,来打破这一机制。

2、 SPI就是打破了双亲委托机制的(SPI:服务提供发现)。

18、Hibernate中Session的load和get方法的区别是什么?

如果没有找到符合条件的记录,get方法返回null,load方法抛出异常。

get方法直接返回实体类对象,load方法返回实体类对象的代理。

在Hibernate 3之前,get方法只在一级缓存中进行数据查找,如果没

有找到对应的数据则越过二级缓存,直接发出SQL语句完成数据读取;

load方法则可以从二级缓存中获取数据;从Hibernate 3开始,get

方法不再是对二级缓存只写不读,它也是可以访问二级缓存的。

19、说一下堆内存中对象的分配的基本策略

eden区、s0区、s1区都属于新生代,tentired 区属于老年代。大部

分情况,对象都会首先在 Eden 区域分配,在一次新生代垃圾回收后,

如果对象还存活,则会进入 s0 或者 s1,并且对象的年龄还会加

1(Eden区->Survivor 区后对象的初始年龄变为1),当它的年龄增加

到一定程度(默认为15岁),就会被晋升到老年代中。对象晋升到老

年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。

另外,大对象和长期存活的对象会直接进入老年代。

20、Java 中如何将字符串转换为整数?

String s="123";

int i;

第一种方法:i=nt(s);

第二种方法:i=f(s).intValue();

21、什么是ThreadPoolExecutor?

ThreadPoolExecutor就是线程池

ThreadPoolExecutor其实也是JAVA的一个类,我们一般通过

Executors工厂类的方法,通过传入不同的参数,就可以构造出适用于

不同应用场景下的ThreadPoolExecutor(线程池)

构造参数图:

构造参数参数介绍:

corePoolSize 核心线程数量 maximumPoolSize 最大线程数量

keepAliveTime 线程保持时间,N个时间单位 unit 时间单位(比如

秒,分) workQueue 阻塞队列 threadFactory 线程工厂 handler

线程池拒绝策略

22、invokedynamic 指令是干什么的?

Java 7 开始,新引入的字节码指令,可以实现一些动态类型语言的功

能。Java 8 的 Lambda 表达式就是通过 invokedynamic 指令实现,

使用方法句柄实现。

23、synchronized、volatile、CAS 比较

1、 synchronized 是悲观锁,属于抢占式,会引起其他线程阻塞。

2、 volatile 提供多线程共享变量可见性和禁止指令重排序优化。

3、 CAS 是基于冲突检测的乐观锁(非阻塞)

24、Iterator 怎么使用?有什么特点?

Iterator 使用代码如下:

List list = new ArrayList<>(); Iterator it = list、

iterator(); while(it、hasNext()){ String obj = it、next(); System、out、

println(obj); }

Iterator 的特点是只能单向遍历,但是更加安全,因为它可以确保,在

当前遍历的集合元素被更改的时候,就会抛出

ConcurrentModificationException 异常。

25、被引用的对象就一定能存活吗?

不一定,看 Reference 类型,弱引用在 GC 时会被回收,软引用在内

存不足的时候,即 OOM 前会被回收,但如果没有在 Reference

Chain 中的对象就一定会被回收。

26、列出一些你常见的运行时异常?

1、 ArithmeticException(算术异常)

2、 ClassCastException (类转换异常)

3、 IllegalArgumentException (非法参数异常)

4、 IndexOutOfBoundsException (下标越界异常)

5、 NullPointerException (空指针异常)

6、 SecurityException (安全异常)

27、Servlet生命周期内调用的方法过程?

1、 Init()

2、 Service()

3、 doGet或者doPost

4、 destroy

28、阐述静态变量和实例变量的区别。

静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不

属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存

中有且仅有一个拷贝;实例变量必须依存于某一实例,需要先创建对象

然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。

补充:在Java开发中,上下文类和工具类中通常会有大量

的静态成员。

29、类加载器双亲委派模型机制?

基本定义:

双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,

它首先不会自己去加载这个类,而是把请求委托给父加载器去完成,依

次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加

载器中,只有当父加载器没有找到所需的类时,子加载器才会尝试去加

载该类。

双亲委派机制:

1、 当 AppClassLoader 加载一个 class 时,它首先不会自己去尝试

加载这个类,而是把类加载请求委派给父类加载器 ExtClassLoader 去

完成。

2、 当 ExtClassLoader 加载一个 class 时,它首先也不会自己去尝

试加载这个类,而是把类加载请求委派给 BootStrapClassLoader 去

完成。

3、 如果 BootStrapClassLoader 加载失败,会使用 ExtClassLoader

来尝试加载;

4、 若 ExtClassLoader 也加载失败,则会使用 AppClassLoader 来

加载,如果 AppClassLoader 也加载失败,则会报出异常

ClassNotFoundException。

如下图所示:

双亲委派作用:

1、 通过带有优先级的层级关可以避免类的重复加载;

2、 保证 Java 程序安全稳定运行,Java 核心 API 定义类型不会被随

意替换。

30、抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方

法(native),是否可同时被synchronized修饰?

都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此

二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽

象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节

有关,抽象方法不涉及实现细节,因此也是相互矛盾的。

本文标签: 对象方法线程使用面试题