目前市面上的JAVA面试题不是答案不准确就是内容覆盖面太窄,所以提供一份经典而又准确的面试题是非常有必要的,本文会对部分面试题提供详细解读和代码案例,让读者知其然并知其所以然,从而学到更多的知识。或许这份面试题还不足以囊括所有Java 问题,但有了它,我相信你一定不会“败”的很惨,因为有了它,足以应对目前市面上绝大部分的Java面试了,因为这篇文章不论是从深度还是广度上来讲,都已经囊括了非常多的知识点了。相信你的每一步努力,都会收获意想不到的回报。
适宜阅读人群:
1.需要面试的初/中/高级Java程序员
2.想要查漏补缺的人
3.想要不断完善和扩充自己Java技术栈的人
4Java面试官
阅读建议:
本文会按技能模块划分文章段落,每个模块里的内容,从易到难依次进行排序, 各模块之间不存在互相关联的关系,读者可选择文章顺序阅读或者跳跃式阅读。包含的模块
本文分为十九个模块,分别是:Java基础、容器、多线程、反射、对象拷贝、Java Web 、异常、网络、设计模式、Spring/Spnng MVC、Spring Boot/Spring Clouds Hibernate s MyBatis、RabbitMQ、Kafka、Zookeeper、MySQL、Redis、
JVM ,如下图所示:
Spring MVC
Spring O Spring Boot
Spring Cloud
RabbitMQ
中间件O Kafka
Zookeeper
Mysql Redis
JVM
共包含208道面试题,本文的宗旨是为读者朋友们整理一份详实而又权威的面 试清单,下面一起进入主题吧。
Java 基础
容器 多线程
对象拷贝
Java e --------
Java Web
异常模块 网络模块 设计模武
面试题
Hibernate Mybatis
Java基础
1JDK和JRE有什么区别?
JDK : Java Development Kit的简称,Java开发工具包,提供了Java的开发环境和运行环境。
JRE : Java Runtime Environment的简称,Java运行环境,为Java的运行提供了所需环境。
具体来说JDK其实包含了JRE,同时还包含了编译Java源码的编译器Javac, 还包含了很多Java程序调试和分析的工具。简单来说:如果你需要运行Java 程序,只需安装JRE就可以了,如果你需要编写Java程序,需要安装JDK。
2. = =和equals的区别是什么?
二二解读
对于基本类型和引用类型二二的作用效果是不同的,如下所示:
基本类型:比较的是值是否相同;
引用类型:比较的是引用是否相同;
代码示例:
String x = "string";
String y ="string”;
String z = new String(u string");
System.out.println(xy); //true
System.out.println(xz); //false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true 代码解读:因为x和y指向的是同一个引用,所以二二也是true,而new String。方法则重写开辟了内存空间,所以二二结果为false,而equals比较的一直是值,所以结果都为true。
equals解读
equals本质上就是==,只不过Stnng和Integer等重写了equals方法,把它变成了值比较。看下面的代码就明白了。
首先来看默认情况下equals比较一个有相同值的对象,代码如下:
class Cat {
public Cat(String name) {
https://www.sodocs.net/doc/f79706689.html, = name;
)
private String name;
public String getName() {
return name;
)
public void setName(String name) {
https://www.sodocs.net/doc/f79706689.html, = name:
)
)
Cat cl = new Cat(“王磊)
Cat c2 = new Cat(“王磊)
System.out.println(cl.equals(c2)); // false
输出结果出乎我们的意料,竟然是false?这是怎么回事,看了equals源码就知道了,源码如下:
public boolean equals(Object obj) {
return (this == obj);
)
原来equals本质上就是二二。
那问题来了,两个相同值的String对象,为什么返回的是true ?代码如下:String si = new String(“老王)
String s2 = new String(“老王)
System.out.println(sl.equals(s2)); // true
同样的,当我们进入String的equals方法,找到了答案.代码如下:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
)
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) { char vl^ = value; charv2口= anotherString.value;
inti = 0;
while (n-- != 0) {
if (vl[i] != v2[i])
return false;
i++;
)
return true;
)
)
return false;
)
原来是String重写了Object的equals方法,把引用比较改成了值比较。
总结:二二对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而equals 默认情况下是引用比较,只是很多类重新了equals方法,比如String、Integer等把它变成了值比较,所以一般情况下equals比较的是值是否相等。
3.两个对象的hashCode()相同,则equalsO也一定为true,对吗?
不对,两个对象的hashCodeO相同,equals。不一定true。
代码示例:
String strl ="通话
String str2 = "重地*
System, out. println(String. format(M strl : %d | str2 : %d", strl. hashCode(),str2. hashCodeQ));
System. out. println(strl. equals(str2));
执行的结果:
strl : 1179395 | str2 : 1179395
false
代码解读很显然“通话”和"重地”的hashCodeQ相同,然而equals()则为false, 因为
在散列表中,hashCodeQ相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能
得出键值对相等。
4.final在Java中有什么作用?
final修饰的类叫最终类,该类不能被继承。
final修饰的方法不能被重写。
final修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。
5Java 中的Math. round(-l, 5)等于多少?
等于-L Math. round四舍五入大于0.5向上取整的。
5.String属于基础的数据类型吗?
String不属于基础类型,基础类型有8种:byte、boolean s char、short、int、float、long、double,而String 属于对象。
7Java中操作字符串都有哪些类?它们之间有什么区别?
操作字符串的类有:String X String Buffer x String Builder。
String和String Buffer StnngBuilder的区别在于String声明的是不可变的对象,每次操作都会生成新的String对象,然后将指针指向新的String对象,而
String Buffer. StringBuilder可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用String o
String Buffer和StringBuilder最大的区别在于,StringBuffer是线程安全的,而
StringBuilder是非线程安全的,但StringBuilder的性能却高于StringBuffer,所以在单线程环境下推荐使用StringBuilder,多线程环境下推荐使用StringBuffer。
6.String stU'i"与String str=new String(T)一样吗?
不一样,因为内存的分配方式不一样。String str=7的方式,Java虚拟机会将其分配到常量池中;而String str=new String(u i")则会被分到堆内存中。
9.如何将字符串反转?
使用StringBuilder 或者StringBuffer 的reverse。方法。
示例代码:
// StringBuffer reverse
StringBuffer StringBuffer = new StringBufferO;
StringBuffer. append(M abcdefg");
System, out. println(stringBuffer. reverse()); // gfedcba
// StringBuilder reverse
StringBuilder StringBuilder = new StringBuilder();
StringBuilder. append(M abcdefg");
System, out. println(stringBuilder. reverse()); // gfedcba
10. String类的常用方法都有那些?
indexOf():返回指定字符的索引。
charAtQ :返回指定索引处的字符。
replaceQ :字符串替换。
trimO :去除字符串两端空白。
spht():分割字符串,返回一个分割后的字符串数组。
getBytesO :返回字符串的byte类型数组。
lengthO :返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substringO :截取字符串。
equals():字符串比较。
11.抽象类必须要有抽象方法吗?
不需要,抽象类不一定非要有抽象方法。
示例代码:
abstract class Cat {
public static void sayHi() {
System, out. println(u hi-");
)
)
上面代码,抽象类并没有抽象方法但完全可以正常运行。
12.普通类和抽象类有哪些区别?
普通类不能包含抽象方法,抽象类可以包含抽象方法。
抽象类不能直接实例化,普通类可以直接实例化。
13.抽象类能使用final修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为final该类就不能被继承, 这样彼此就会产生矛盾,所以final不能修饰抽象类,如下图所示,编辑器也会
提示错误信息:
编译器保存图
14.接口和抽象类有什么区别?
默认方法实现:抽象类可以有默认的方法实现;接口不能有默认的方法实现。
实现:抽象类的子类使用extends来继承;接口必须使用implements来实现接口。
构造函数:抽象类可以有构造函数;接口不能有。
main方法:抽象类可以有main方法,并且我们能运行它;接口不能有mam 方法。
实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
访问修饰符:接口中的方法默认使用public修饰;抽象类中的方法可以是任意访问修饰符。
15Java中10流分为几种?
按功能来分:输入流(input) s输出流(output) o
按类型来分:字节流和字符流。
字节流和字符流的区别是:字节流按8位传输以字节为单位输入输出数据,字符流按16位传输以字符为单位输入输出数据。
15.BI0. NIO、AI0有什么区别?
BI0 : Block 10同步阻塞式10,就是我们平常使用的传统10,它的特点是模式简单使用方便,并发处理能力低。
NI0 : New 10同步非阻塞是传统10的升级,客户端和服务器端通过
Channel (通道)通讯,实现了多路复用。
AIO : Asynchronous 10是NI0的升级,也叫NI02,实现了异步非堵塞10
异步。的操作基于事件和回调机制。
17.Files的常用方法都有哪些?
Files. existsQ :检测文件路径是否存在。Files, createFile():创建文件。
Files. createDirectoryO :创建文件夹。Files. deleteO :删除一个文件或目录。Files. copyO :复制文件。
Files. move():移动文件。
Files. sizeO :查看文件个数。
Files. read():读取文件。
Files. write():写入文件。
容器
18Java容器都有哪些?
Java容器分为Collection和Map两大类,其下又有很多子类,如下所示:Collection
List
Array Li st
LinkedList
Vector
Stack
Set
HashSet
LinkedHashSet
TreeSet
Map
HashMap
LinkedHashMap
TreeMap
ConcurrentHash Map
Hashtable
19.Collection 和Collections 有什么区别?
Collection是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法, 所有集合都是它的子类,比如List、Set等。
Collections是一个包装类,包含了很多静态方法,不能被实例化,就像一个工具
类,比如提供的排序方法:Collections. sort(list)0
20.Lists Sets Map之间的区别是什么?
Lists Sets Map的区别主要体现在两个方面:元素是否有序、是否允许元素重复。
三者之间的区别,如下表:
区别图
21.Hash Map 和Hashtable 有什么区别?
存储:HashMap 运行key 和value 为null,而Hashtable 不允许。
线程安全:Hashtable是线程安全的,而HashMap是非线程安全的。
推荐使用:在Hashtable的类注释可以看到,Hashtable是保留类不建议使用,推荐在单线程环境下使用HashMap替代,如果需要多线程使用则用ConcurrentHashMap 替代。
22.如何决定使用HashMap还是TreeMap ?
对于在Map中插入、删除、定位一个元素这类操作,HashMap是最好的选择,因为相对而言HashMap的插入会更快,但如果你要对一个key集合进行有序的遍历,那TreeMap是更好的选择。
23.说一下HashMap的实现原理?
HashMap基于Hash算法实现的,我们通过put(key,value)存储,get(key)来获
取。当传入key时,HashMap会根据key. hashCodeQ计算出hash值,根据hash值将value保存在bucket里,当计算出的hash值相同时,我们称之为hash冲突,Hash Map的做法是用链表和红黑树存储相同hash值的value。当hash冲突的个数比较少时,使用链表否则使用
红黑树。
24说一下Hash Set的实现原理?
HashSet是基于HashMap实现的,HashSet底层使用Hash Map来保存所有元素,因此HashSet 的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成,HashSet不允许重复的值。
2 5. Array Li st 和LinkedList 的区别是什么?
数据结构实现:ArrayList是动态数组的数据结构实现,而LinkedList是双向链表的数据结构实现。
随机访问效率:ArrayList比LinkedList在随机访问的时候效率要高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。
增加和删除效率:在非首尾的增加和删除操作,LinkedList要比ArrayList效率要高,因为ArrayList增删操作要影响数组内的其他数据的下标。
综合来说,在需要频繁读取集合中的元素时,更推荐使用ArrayList,而在插入和
删除操作较多时,更推荐使用LinkedList o
26.如何实现数组和List之间的转换?
数组转List :使用Arrays. asList(array)进行转换。
List转数组:使用List自带的toArrayO方法。
代码示例:
// list to array
List list = new Array Li st();
list, add(“王磊)
list, add("的博客)
list, to Array 0;
// array to list
String口array = new String口{“王磊丁的博客”};
Arrays. asList(array);
27. Array Li st和Vector的区别是什么?
线程安全:Vector使用了Synchronized来实现线程同步,是线程安全的,而Array Li st是非线程安全的。
性能:ArrayList在性能方面要优于Vector。
扩容:ArrayList和Vector都会根据实际的需要动态的调整容量,只不过在Vector扩容每次会增加1倍,而ArrayList只会增加50%。
28. Array 和ArrayList 有何区别?
Array可以存储基本数据类型和对象,ArrayList只能存储对象。
Array是指定固定大小的,而ArrayList大小是自动扩展的。
Array内置方法没有ArrayList多,比如addAIK removeAIK iteration等方法只有ArrayList 有。
29.在Queue中poll。和remove。有什么区别?
相同点:都是返回第一个元素,并在队列中删除返回的对象。
不同点:如果没有元素poll()会返回null ,而remove()会直接抛出
NoSuch日ementException 异常。
代码示例:
Queue queue = new LinkedList();
queue. offer(M string w); 〃 add
System. out. println(queue. pollO);
System. out. println(queue. removeO);
System. out. println(queue. size());
30.哪些集合类是线程安全的?
Vector^ Hashtable x Stack都是线程安全的,而像Hash Map则是非线程安全的,
不过在JDK1.5之后随着Java. util, concurrent并发包的出现,它们也有了自己对应的线程安全类,比如HashMap对应的线程安全类就是ConcurrentHash Map o
31.迭代器Iterator是什么?
Iterator接口提供遍历任何Collection的接口。我们可以从一个Collection中使用迭代器方法来获取迭代器实例。迭代器取代了Java集合框架中的Enumeration,迭代器允许调用者在迭代过程中移除元素。
32. Iterator怎么使用?有什么特点?
Iterator使用代码如下:
List list = new ArrayList<>();
Iterator it = list. iterator();
while(it. hasNextQ){
String obj = it. nextO;
System. out. println(obj);
Iterator的特点是更加安全,因为它可以确保.在当前遍历的集合元素被更改的
时候,就会抛出ConcurrentModification Exception 异常。
33. Iterator 和Li st Iterator 有什么区别?
Iterator可以遍历Set和List集合,而Listiterator只能遍历List。
Iterator只能单向遍历,而Li st Iterator可以双向遍历(向前/后遍历)。
Listiterator从Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。
34,怎么确保一个集合不能被修改?
可以使用Collections, unmod币ableCollection(Collection c)方法来创建一个只读集合,这样改变集合的任何操作都会抛出Java. lang. UnsupportedOperationException 异常。
示例代码如下:
List list = new ArrayList<>();
list. add(V);
Collection clist = Collections. unmodifiableCollection(list);
clist. add(y); //运行时此行报错
System, out. println(list. sizeQ);多线程
35.并行和并发有什么区别?
并行:多个任务在同一个CPU核上,按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行。
并发:多个处理器或多核处理器同时处理多个任务。
如下图:
并发和并行
并发二两个队列和一台咖啡机。
并行=两个队列和两台咖啡机。
36.线程和进程的区别?
一个程序下至少有一个进程,一个进程下至少有一个线程,一个进程下也可以有多个线程来增加程序的执行速度。
37.守护线程是什么?
守护线程是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。在Java中垃圾回收线程就是特殊的守护线程。
38.创建线程有哪几种方式?
创建线程有三种方式:
继承Thread重新run方法;实现Runnable 接口;实现Callable 接口。
39.说一下runnable和callable有什么区别?
runnable没有返回值,callable可以拿到有返回值,callable可以看作是runnable的补充。
40.线程有哪些状态?
线程的状态:
NEW尚未启动
RUNNABLE正在执行中
BLOCKED阻塞的(被同步锁或者10锁阻塞)
WAITING永久等待状态
TIMED.WAITING等待指定的时间重新被唤醒的状态
TERMINATED执行完成
41. sleepO和waitO有什么区别?
类的不同:sleep()来自Thread, wait。来自Object o
释放锁:sleepO不释放锁;waitO释放锁。
用法不同:sleepO时间到会自动恢复;waitO可以使用notifyO/notifyAII。直接唤醒。42. notify。和notifyAII。有什么区别?
notifyAII。会唤醒所有的线程,notify。之后唤醒一个线程。notifyAII。调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify。只会唤醒一个线程, 具体唤醒哪一个线程由虚拟机控制。
43.线程的runO和startQ有什么区别?
startO方法用于启动线程,run。方法用于执行线程的运行时代码。run()可以重复调用,而startO只能调用一次。
44.创建线程池有哪几种方式?
线程池创建有七种方式,最核心的是最后一种:
n ewSi n gl eTh re ad ExecutorO :它的特点在于工作线程数目被限制为1,操作一个无界的工作队列,所以它保证了所有任务的都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目;newCachedThreadPoolO :它是一种用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置的时间超过60秒,则被终止并移出缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用SynchronousQueue作为工作队列;
newFixedThreadPool(int nThreads):重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有nThreads个工作线程是活动的。这意味着,如果任务数量超过了活动队列数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工
作线程被创建,以补足指定的数目nThreads ;newSingleThreadScheduledExecutorO :创建单线程池,返回ScheduledExecutorService,可以进行定时或周期性的工作调度;newScheduledThreadPool(int corePoolSize) : 和newSingleThreadScheduledExecutorQ 类似
创建的是个ScheduledExecutorService,可以进行定时或周期性的工作调
度,区别在于单一工作线程还是多个工作线程;
newWorkStealingPool(int parallelism):这是一个经常被人忽略的线程池,Java 8 才加入这个创建方法,其内部会构建ForkJomPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序;
ThreadPoolExecutorO :是最原始的线程池创建,上面1-3创建方式都是对ThreadPoolExecutor 的封装。
45.线程池都有哪些状态?
RUNNING :这是最正常的状态,接受新的任务,处理等待队列中的任务。
SHUTDOWN :不接受新的任务提交,但是会继续处理等待队列中的任务。
STOP :不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。TIDYING :所有的任务都销毁了,workCount为0,线程池的状态在转换为
TIDYING状态时,会执行钩子方法terminatedOo
TERMINATED : terminated。方法结束后,线程池的状态就会变成这个。
46,线程池中submit()和execute()方法有什么区别?
executeQ :只能执行Runnable类型的任务。
submit():可以执行Runnable和Callable类型的任务。
Callable类型的任务可以获取执行的返回值,而Runnable执行无返回值。