本文整理了 Java 核心技术点的常见面试题,涵盖以下模块:
- Java 基础、容器、多线程、反射、对象拷贝
- Java Web、异常、网络、设计模式
- Spring/Spring MVC、Spring Boot/Spring Cloud
- Hibernate、MyBatis、RabbitMQ、Kafka、Zookeeper
- MySQL、Redis、JVM
Java 基础
1. JDK 和 JRE 有什么区别?
- JDK(Java Development Kit):开发工具包,提供开发环境和运行环境。
- JRE(Java Runtime Environment):运行环境,为 Java 程序运行提供支持。
JDK 实际上包含了 JRE,同时还提供了编译器 javac 以及调试分析工具。简单来说,若只需运行程序安装 JRE 即可;若要编写代码,则需安装 JDK。
2. == 和 equals 的区别是什么?
== 解读 对于基本类型和引用类型,== 的作用效果不同:
- 基本类型:比较值是否相同。
- 引用类型:比较引用地址是否相同。
String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x == y); // true
System.out.println(x == z); // 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 本质上就是 ==,但 String、Integer 等类重写了该方法,将其变为值比较。
默认情况下,Object 类的 equals 源码如下:
public boolean equals(Object obj) {
return (this == obj);
}
因此两个自定义对象即使内容相同,默认 equals 也会返回 false。而 String 类重写了 equals 方法,逐字符比较内容,所以返回 true。
总结:== 对基本类型比值,对引用类型比地址;equals 默认比地址,但多数类已重写为比值。
3. 两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?
不对。hashCode() 相同仅表示哈希值相等,不代表对象内容一致。
String str1 = "通话";
String str2 = "重地";
System.out.println(String.format("str1:%d | str2:%d", str1.hashCode(), str2.hashCode()));
System.out.println(str1.equals(str2));
执行结果显示两者 hashCode 相同但 equals 为 false。在散列表中,哈希冲突是常见现象,不能仅凭哈希值判断对象相等。
4. final 在 Java 中有什么作用?
- 修饰类:该类不能被继承(最终类)。
- 修饰方法:该方法不能被重写。
- 修饰变量:成为常量,必须初始化且值不可修改。
5. Java 中的 Math.round(-1.5) 等于多少?
等于 -1。Math.round 采用四舍五入规则,中间值(0.5)向正无穷方向取整,负 0.5 直接舍弃小数部分。
6. String 属于基础的数据类型吗?
不属于。Java 有 8 种基本数据类型:byte、boolean、char、short、int、float、long、double。String 属于对象。
7. Java 中操作字符串都有哪些类?它们之间有什么区别?
主要有 String、StringBuffer、StringBuilder。
- String:不可变对象,每次修改都会生成新对象,指针指向新对象。
- StringBuffer:可变对象,线程安全,性能略低。
- StringBuilder:可变对象,非线程安全,性能高于 StringBuffer。
频繁修改字符串时,建议使用 StringBuilder(单线程)或 StringBuffer(多线程)。
8. String str="i"与 String str=new String('i')一样吗?
不一样,内存分配方式不同。
String str="i":分配到常量池中。String str=new String("i"):分配到堆内存中。
9. 如何将字符串反转?
使用 StringBuilder 或 StringBuffer 的 reverse() 方法。
// StringBuilder 示例
StringBuilder sb = new StringBuilder();
sb.append("abcdefg");
System.out.println(sb.reverse()); // gfedcba
10. String 类的常用方法有哪些?
- indexOf():返回指定字符索引。
- charAt():返回指定索引字符。
- replace():替换字符串。
- trim():去除两端空白。
- split():分割字符串。
- getBytes():转为 byte 数组。
- length():获取长度。
- toLowerCase()/toUpperCase():大小写转换。
- substring():截取子串。
- equals():比较内容。
11. 抽象类必须要有抽象方法吗?
不需要。抽象类可以没有抽象方法,但不能直接实例化。
abstract class Cat {
public static void sayHi() {
System.out.println("hi~");
}
}
12. 普通类和抽象类有哪些区别?
- 普通类不能包含抽象方法,抽象类可以。
- 普通类可直接实例化,抽象类不能。
13. 抽象类能使用 final 修饰吗?
不能。final 禁止继承,而抽象类旨在被继承,二者矛盾。
14. 接口和抽象类有什么区别?
- 实现方式:抽象类用 extends,接口用 implements。
- 构造函数:抽象类可以有,接口不能有。
- 继承数量:类可实现多个接口,但只能继承一个抽象类。
- 访问修饰符:接口方法默认为 public,抽象类方法可任意修饰。
15. Java 中 IO 流分为几种?
按功能分:输入流(input)、输出流(output)。 按类型分:字节流(8 位)、字符流(16 位)。
16. BIO、NIO、AIO 有什么区别?
- BIO(Block IO):同步阻塞式 IO,传统模式,并发能力低。
- NIO(Non Blocking IO):同步非阻塞 IO,基于 Channel 多路复用。
- AIO(Asynchronous IO):异步非阻塞 IO,基于事件和回调机制。
17. Files 的常用方法有哪些?
- exists():检测路径是否存在。
- createFile()/createDirectory():创建文件/目录。
- delete():删除文件或目录。
- copy()/move():复制/移动文件。
- size():查看文件大小。
- read()/write():读写文件。
容器
18. Java 容器都有哪些?
主要分为 Collection 和 Map 两大类。
- Collection:List(ArrayList, LinkedList, Vector, Stack)、Set(HashSet, LinkedHashSet, TreeSet)。
- Map:HashMap, LinkedHashMap, TreeMap, ConcurrentHashMap, Hashtable。
19. Collection 和 Collections 有什么区别?
- Collection:集合接口,提供基本操作通用方法,如 List、Set 均是其子类。
- Collections:包装类,包含静态工具方法,如排序,不可实例化。
20. List、Set、Map 之间的区别是什么?
主要体现在元素有序性和重复性上:
- List:有序,允许重复。
- Set:无序(HashSet),不允许重复。
- Map:键值对,Key 唯一,Value 可重复。
21. HashMap 和 Hashtable 有什么区别?
- Null 支持:HashMap 允许 key/value 为 null,Hashtable 不允许。
- 线程安全:Hashtable 线程安全,HashMap 非线程安全。
- 推荐:Hashtable 已过时,单线程用 HashMap,多线程用 ConcurrentHashMap。
22. 如何决定使用 HashMap 还是 TreeMap?
- HashMap:插入、删除、定位效率高,无序。
- TreeMap:按键排序遍历,适合需要有序场景。
23. 说一下 HashMap 的实现原理?
基于 Hash 算法。put(key, value) 时计算 key.hashCode() 得到 hash 值,存入 bucket。hash 冲突时使用链表或红黑树存储。冲突少时用链表,多时转红黑树。
24. 说一下 HashSet 的实现原理?
基于 HashMap 实现。底层用 HashMap 保存元素,key 即为 Set 元素,value 为固定 Object。不允许重复值。
25. ArrayList 和 LinkedList 的区别是什么?
- 数据结构:ArrayList 是动态数组,LinkedList 是双向链表。
- 随机访问:ArrayList 效率高(O(1)),LinkedList 需遍历(O(n))。
- 增删效率:非首尾操作 LinkedList 更优,ArrayList 需移动数据。
建议频繁读取用 ArrayList,频繁增删用 LinkedList。
26. 如何实现数组和 List 之间的转换?
- 数组转 List:Arrays.asList(array)。
- List 转数组:list.toArray()。
// list to array
List<String> list = new ArrayList<>();
list.add("test");
list.toArray();
// array to list
String[] array = {"a", "b"};
Arrays.asList(array);
27. ArrayList 和 Vector 的区别是什么?
- 线程安全:Vector 使用 synchronized 同步,线程安全;ArrayList 非线程安全。
- 性能:ArrayList 优于 Vector。
- 扩容:Vector 扩容 1 倍,ArrayList 扩容 50%。
28. Array 和 ArrayList 有何区别?
- 类型:Array 存基本类型和对象,ArrayList 只存对象。
- 大小:Array 固定,ArrayList 自动扩展。
- 方法:ArrayList 提供更多内置方法(addAll、removeAll 等)。
29. 在 Queue 中 poll() 和 remove() 有什么区别?
- poll():返回第一个元素并删除,无元素返回 null。
- remove():返回第一个元素并删除,无元素抛出 NoSuchElementException。
30. 哪些集合类是线程安全的?
Vector、Hashtable、Stack 是线程安全的。JDK 1.5 后并发包提供了 ConcurrentHashMap 替代 Hashtable。
31. 迭代器 Iterator 是什么?
Iterator 接口提供遍历 Collection 的方法,取代了 Enumeration,支持在遍历中移除元素。
32. Iterator 怎么使用?有什么特点?
List<String> list = new ArrayList<>();
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String obj = it.next();
System.out.println(obj);
}
特点是更安全,遍历中修改集合会抛出 ConcurrentModificationException。
33. Iterator 和 ListIterator 有什么区别?
- 范围:Iterator 遍历 Set 和 List,ListIterator 仅遍历 List。
- 方向:Iterator 单向,ListIterator 双向。
- 功能:ListIterator 支持添加、替换元素及获取索引。
34. 怎么确保一个集合不能被修改?
使用 Collections.unmodifiableCollection(Collection c) 创建只读集合,任何修改操作将抛出 UnsupportedOperationException。
多线程
35. 并行和并发有什么区别?
- 并行:多核处理器同时处理多个任务。
- 并发:单核 CPU 通过时间片轮流执行多个任务,逻辑上同时。
36. 线程和进程的区别?
一个程序至少有一个进程,一个进程至少有一个线程。线程增加程序执行速度,共享进程资源。
37. 守护线程是什么?
后台运行的特殊进程,独立于控制终端,周期执行任务。例如垃圾回收线程。
38. 创建线程有哪几种方式?
- 继承 Thread 类并重写 run 方法。
- 实现 Runnable 接口。
- 实现 Callable 接口。
39. 说一下 runnable 和 callable 有什么区别?
Runnable 无返回值,Callable 可返回结果。Callable 可视为 Runnable 的补充。
40. 线程有哪些状态?
- NEW:尚未启动。
- RUNNABLE:正在执行。
- BLOCKED:被锁或 IO 阻塞。
- WAITING:永久等待。
- TIMED_WAITING:等待指定时间。
- TERMINATED:执行完成。
41. sleep() 和 wait() 有什么区别?
- 来源:sleep() 来自 Thread,wait() 来自 Object。
- 锁:sleep() 不释放锁,wait() 释放锁。
- 唤醒:sleep() 时间到自动恢复,wait() 需 notify()/notifyAll() 唤醒。
42. notify() 和 notifyAll() 有什么区别?
notify() 唤醒一个线程,具体由 JVM 决定;notifyAll() 唤醒所有等待线程,全部进入锁池竞争。
43. 线程的 run() 和 start() 有什么区别?
start() 启动线程,run() 执行代码。run() 可重复调用,start() 只能调用一次。
44. 创建线程池有哪几种方式?
最核心的是 ThreadPoolExecutor,其他多为封装:
- newSingleThreadExecutor():单线程,顺序执行。
- newCachedThreadPool():缓存线程,大量短时任务。
- newFixedThreadPool(int nThreads):固定线程数。
- newScheduledThreadPool():定时或周期性调度。
- newWorkStealingPool():工作窃取,并行处理。
45. 线程池都有哪些状态?
- RUNNING:接受新任务,处理队列。
- SHUTDOWN:不接受新任务,处理队列。
- STOP:不接受新任务,中断任务。
- TIDYING:任务销毁,workCount 为 0。
- TERMINATED:terminated() 结束。
46. 线程池中 submit() 和 execute() 方法有什么区别?
- execute():仅执行 Runnable。
- submit():可执行 Runnable 和 Callable,后者可获取返回值。
47. 在 Java 程序中怎么保证多线程的运行安全?
- 使用 java.util.concurrent 安全类。
- 使用 synchronized 自动锁。
- 使用 Lock 手动锁。
Lock lock = new ReentrantLock();
lock.lock();
try {
System.out.println("获得锁");
} finally {
lock.unlock();
}
48. 多线程中 synchronized 锁升级的原理是什么?
JDK 6 优化了 synchronized,引入偏向锁、轻量级锁、重量级锁。
- 偏向锁:首次访问设置线程 ID,再次访问直接持有。
- 轻量级锁:不一致时自旋循环尝试获取。
- 重量级锁:自旋失败后升级为重量级,依赖操作系统互斥锁。 目的是降低锁带来的性能消耗。
49. 什么是死锁?
线程 A 持有锁 a 请求锁 b,线程 B 持有锁 b 请求锁 a,互相阻塞无法继续。
50. 怎么防止死锁?
- 使用 tryLock 设置超时。
- 优先使用并发包类。
- 降低锁粒度,避免多锁共用。
- 减少同步代码块。
51. ThreadLocal 是什么?有哪些使用场景?
为每个线程提供独立变量副本,互不影响。经典场景:数据库连接管理、Session 管理。
52. 说一下 synchronized 底层实现原理?
基于 monitorenter/monitorexit 指令。Java 6 前依赖操作系统互斥锁(重量级),6 后引入三种锁优化性能。
53. synchronized 和 volatile 的区别是什么?
- 修饰:volatile 修饰变量,synchronized 修饰类/方法/代码块。
- 原子性:volatile 仅保证可见性,synchronized 保证可见性与原子性。
- 阻塞:volatile 不阻塞,synchronized 可能阻塞。
54. synchronized 和 Lock 有什么区别?
- 范围:synchronized 可修饰类/方法/块,Lock 仅代码块。
- 释放:synchronized 异常自动释放,Lock 需手动 unlock。
- 查询:Lock 可查询是否获取成功,synchronized 不行。
55. synchronized 和 ReentrantLock 区别是什么?
- 灵活性:ReentrantLock 更灵活,但需配合 unlock。
- 用法:synchronized 无需手动释放,ReentrantLock 必须手动释放。
- 范围:ReentrantLock 仅代码块,synchronized 覆盖更广。
56. 说一下 atomic 的原理?
利用 CAS(Compare And Swap)和 volatile 及 native 方法保证原子操作,避免 synchronized 高开销,提升效率。
反射
57. 什么是反射?
运行时动态获取类的所有属性和方法,并能调用任意对象的方法。这种机制称为反射。
58. 什么是 Java 序列化?什么情况下需要序列化?
保存对象内存状态以便后续还原。适用场景:
- 保存到文件或数据库。
- 通过网络套接字传输。
- RMI 远程调用。
59. 动态代理是什么?有哪些应用?
运行时动态生成代理类。应用包括 Spring AOP、Hibernate 查询、RPC、注解处理等。
60. 怎么实现动态代理?
- JDK 原生代理:基于接口。
- CGLIB 代理:基于继承子类。
对象拷贝
61. 为什么要使用克隆?
当需要保存当前对象状态的新对象时,克隆可保留修改过的属性,而 new 出来的对象是初始状态。
62. 如何实现对象克隆?
- 实现 Cloneable 接口并重写 clone()。
- 实现 Serializable 接口,通过序列化和反序列化实现深度克隆。
63. 深拷贝和浅拷贝区别是什么?
- 浅拷贝:复制对象本身及值类型成员,引用类型成员不复制。
- 深拷贝:复制对象及其所有成员变量,包括引用对象。
Java Web
64. JSP 和 servlet 有什么区别?
JSP 是 Servlet 的扩展,本质仍是 Servlet。
- Servlet:逻辑在 Java 文件,分离 HTML。
- JSP:Java 与 HTML 组合,侧重视图。
65. JSP 有哪些内置对象?作用分别是什么?
共 9 大内置对象:
- request:封装客户端请求参数。
- response:封装服务器响应。
- pageContext:获取其他对象。
- session:封装用户会话。
- application:封装服务器环境。
- out:输出流对象。
- config:Web 配置对象。
- page:页面本身(this)。
- exception:封装异常对象。
66. 说一下 JSP 的 4 种作用域?
- page:页面相关。
- request:单次请求相关。
- session:用户会话相关。
- application:全局应用相关。
67. session 和 cookie 有什么区别?
- 存储位置:session 在服务端,cookie 在浏览器。
- 安全性:cookie 易伪造,session 较安全。
- 容量限制:cookie 有大小和个数限制,session 取决于服务端。
- 多样性:session 可存 Redis/DB,cookie 仅限浏览器。


