Java面试避坑:10个高频“陷阱问题”,答案直接背
1. 面试问题:equals () 和 == 的区别是什么?
坑点分析:
-
新手仅笼统说 “== 比地址,equals 比值”,忽略 Object 类中 equals 的默认实现就是
==; -
漏提 String/Integer 等类重写 equals 的细节,也没说自定义类需重写 equals 的场景;
-
混淆基本数据类型(无 equals 方法)和引用类型的
==规则。
正确答案:
① 作用对象:
-
==:可比较基本数据类型(值是否相等),也可比较引用类型(内存地址是否相等,即是否指向同一对象); -
equals():是 Object 类方法,仅能比较引用类型。
② 实现规则:
-
Object 类中 equals 默认实现:
return this == obj;(和==等价); -
String、Integer、Date 等常用类重写了 equals,改为比较 “对象内容 / 值”;
-
自定义类若需按内容比较,必须手动重写 equals(建议同时重写 hashCode,遵循 “相等对象必须有相等 hashCode”)。
示例:
String s1 = new String("Java");
String s2 = new String("Java");
System.out.println(s1 == s2); // false(地址不同)
System.out.println(s1.equals(s2)); // true(内容相同)
2. 面试问题:String、StringBuffer、StringBuilder 的区别?
坑点分析:
-
仅提 “String 不可变,后两者可变”,漏了线程安全、性能核心维度;
-
误以为 StringBuffer 性能和 StringBuilder 相当;
-
忽略 String 常量池优化(如
String s="a"+"b"会被编译为"ab",指向常量池)。
正确答案:
核心围绕「可变性、线程安全、性能」三个维度:
|
维度 |
String |
StringBuffer |
StringBuilder |
|---|---|---|---|
|
可变性 |
不可变 |
可变 |
可变 |
|
线程安全 |
天然安全 |
安全 |
不安全 |
|
性能 |
拼接频繁创建新对象 |
安全但性能低于StringBuilder |
单线程下性能最高 |
|
适用场景 |
少量字符串操作 |
多线程字符串拼接 |
单线程大量字符串拼接 |
3. 面试问题:重载(Overload)和重写(Override)的区别?
坑点分析:
-
混淆判定规则:认为返回值不同能重载,或重写可修改参数列表;
-
漏提重写的访问修饰符、异常抛出限制;
-
不知道重载是 “编译时多态”,重写是 “运行时多态”。
正确答案:
|
维度 |
重载(Overload) |
重写(Override) |
|---|---|---|
|
定义 |
同一类中,方法名相同、参数列表不同 |
子类重写父类方法,方法名 + 参数列表 + 返回值(协变)完全一致 |
|
核心判定 |
仅看参数列表(个数 / 类型 / 顺序) |
方法签名(名 + 参数)必须完全一致 |
|
返回值 |
无要求(可不同) |
需兼容(如父类返回 Object,子类可返回 String) |
|
访问修饰符 |
无限制 |
子类不能缩小父类方法访问范围(如父类 public,子类不能 private) |
|
异常抛出 |
无限制 |
子类不能抛出更宽泛的 Checked Exception |
|
多态类型 |
编译时多态 |
运行时多态 |
点击下方小卡片免费获取Java资料Java资料
https://mp.weixin.qq.com/s/iBmSycbmeTCSRNKJQ10EuA
4. 面试问题:HashMap 和 Hashtable 的区别?
坑点分析:
-
仅说 “Hashtable 线程安全,HashMap 不是”,漏了 null 键值、初始容量、扩容机制;
-
误以为 HashMap 完全不能用于并发场景,没提 ConcurrentHashMap 的替代方案;
-
不知道 Hashtable 是遗留类,已被淘汰。
正确答案:
HashMap 是 Hashtable 的替代方案(JDK1.2 引入),核心区别:
① 线程安全:
-
Hashtable:方法加 synchronized,线程安全但并发效率低(全局锁);
-
HashMap:非线程安全,并发场景优先用 ConcurrentHashMap(分段锁 / CAS,效率更高)。
② null 支持:
-
Hashtable:不允许 key/value 为 null,否则抛 NPE;
-
HashMap:允许 1 个 null key,多个 null value。
③ 容量与扩容:
-
Hashtable:默认初始容量 11,扩容为
原容量*2+1; -
HashMap:默认初始容量 16,扩容为原容量*2(必须是 2 的幂)。
④ 底层实现:JDK8 后 HashMap 引入红黑树(链表≥8 时),Hashtable 始终是数组 + 链表。
5. 面试问题:线程中 sleep () 和 wait () 的区别?
坑点分析:
-
核心误区:认为 sleep () 会释放锁;
-
漏了所属类、唤醒方式、使用场景的区别;
-
不知道 wait () 必须在同步代码块中调用,sleep () 无此要求。
正确答案:
|
维度 |
sleep() |
wait() |
|---|---|---|
|
所属类 |
Thread 类(静态方法) |
Object 类(所有对象拥有) |
|
锁释放 |
不释放持有的锁 |
必须在 synchronized 中调用,调用后立即释放锁 |
|
唤醒方式 |
休眠时间到自动唤醒 / 被 interrupt () 中断 |
需 notify ()/notifyAll () 唤醒,或 wait (long) 超时自动唤醒 |
|
适用场景 |
固定时间休眠(如定时任务) |
线程间通信(如生产者消费者模型) |
6. 面试问题:Integer a=127, b=127; a==b 为 true?128 呢?为什么?
坑点分析:
-
仅知道结果,说不出底层的自动装箱缓存机制;
-
混淆 int(基本类型)和 Integer(包装类型)的
==比较规则; -
不知道缓存范围可通过 JVM 参数调整。
正确答案:
① 结果:a=127 时a==b→true;a=128 时a==b→false。
② 核心原因:Integer 的自动装箱缓存(IntegerCache):
-
JDK 默认缓存
-128~127之间的 Integer 对象; -
范围内赋值时,直接取缓存对象,==比较地址相等;超出范围则新建对象,地址不同。
③ 补充:
-
比较值需用 equals ()(Integer 重写 equals,比较值);
-
缓存上限(127)可通过-XX:AutoBoxCacheMax=xxx调整,下限固定 - 128。
示例:
Integer a=128, b=128;
System.out.println(a==b); // false
System.out.println(a.equals(b)); // true
7. 面试问题:抽象类(Abstract Class)和接口(Interface)的区别?
坑点分析:
-
仅说 “抽象类单继承,接口多实现”,漏了 JDK8 + 接口的默认方法、静态方法;
-
混淆成员变量 / 方法的修饰符规则;
-
不知道抽象类有构造方法,接口无。
正确答案:
JDK8 + 后核心区别:
|
维度 |
抽象类 |
接口 |
|---|---|---|
|
继承 / 实现 |
单继承 |
多实现 |
|
成员变量 |
任意修饰符(private/public 等) |
JDK8 前:public static final;JDK8+:新增 private 静态变量 |
|
方法 |
可包含抽象 / 普通 / 静态 / 默认方法 |
JDK8 前:仅抽象方法;JDK8+:新增 default / 静态方法;JDK9+:新增 private 方法 |
|
构造方法 |
有(供子类调用) |
无 |
|
设计理念 |
强调 “is-a” 继承(如 Animal→Dog) |
强调 “has-a” 行为契约(如 Runnable) |
8. 面试问题:try-catch-finally 中的 finally 块一定会执行吗?
坑点分析:
-
最大误区:认为 finally 永远执行;
-
漏了导致 finally 不执行的特殊场景;
-
不知道 finally 中 return 会覆盖 try/catch 的 return 值。
正确答案:
finally 并非绝对执行,以下场景不执行:
① try/catch 块执行前,线程被终止(如调用System.exit(0)、JVM 崩溃、断电);
② try 块中调用Thread.stop()(已废弃)。
其他场景(如 try/catch 中有 return/break/continue),finally 都会在 “try/catch 的 return 前” 执行。
关键陷阱:finally 中有 return 会覆盖 try/catch 的 return 值:
public static int test() {
try {
return 1;
} finally {
return 2; // 最终返回2,覆盖try的return 1
}
}
点击下方小卡片免费获取Java资料Java资料
https://mp.weixin.qq.com/s/iBmSycbmeTCSRNKJQ10EuA
9. 面试问题:ArrayList 和 LinkedList 的区别?
坑点分析:
-
仅说 “ArrayList 是数组,LinkedList 是链表”,漏了场景化效率区别;
-
误以为 LinkedList 增删一定比 ArrayList 快;
-
忽略内存占用、遍历方式的影响。
正确答案:
|
维度 |
ArrayList |
LinkedList |
|---|---|---|
|
底层结构 |
动态数组(扩容 1.5 倍) |
双向链表 |
|
随机访问(get (index)) |
高效(O (1)) |
低效(O (n),需遍历) |
|
尾部增删 |
高效(O (1),无扩容时) |
高效(O (1)) |
|
中间增删 |
低效(O (n),移动元素) |
高效(O (1),仅改指针) |
|
内存占用 |
连续空间,有扩容冗余 |
每个节点存 prev/next,开销更大 |
|
适用场景 |
频繁随机访问、少量增删 |
频繁中间增删、少量访问 |
关键提醒:LinkedList 增删快的前提是 “已找到目标节点”,若需先遍历找节点,效率反而低于 ArrayList。
10. 面试问题:Java 异常体系?Checked 和 Unchecked Exception 的区别?
坑点分析:
-
混淆两类异常的定义和处理规则;
-
误以为 RuntimeException 必须捕获;
-
漏了异常体系的继承结构(Throwable→Error/Exception)。
正确答案:
① 异常体系核心结构:
Throwable(顶层)
├─ Error(如OOM、StackOverflowError):JVM严重错误,程序无法处理,无需捕获;
└─ Exception
├─ Checked Exception(如IOException、SQLException):编译时必须处理(捕获/抛出);
└─ Unchecked Exception(RuntimeException及其子类,如NPE、数组越界):编译无需处理,运行时抛出。
② 核心区别:
|
维度 |
Checked Exception |
Unchecked Exception |
|---|---|---|
|
编译检查 |
必须处理 |
无需处理 |
|
产生原因 |
外部环境问题(文件不存在) |
程序逻辑错误(空指针) |
总结
-
Java 面试陷阱题核心集中在细节规则(如 Integer 缓存、finally 执行逻辑)、易混淆概念(重载 / 重写、抽象类 / 接口)、锁与线程安全(sleep/wait、HashMap/Hashtable)三大类;
-
回答陷阱题时,不仅要给结论,还要解释底层原因(如缓存机制、锁释放逻辑),体现对 Java 原理的理解;
-
比较类问题建议按 “维度拆解 + 适用场景” 回答,逻辑更清晰,易被面试官认可。
-
由于篇幅有限,更多资料内容请点击下方小卡片免费获取Java资料
https://mp.weixin.qq.com/s/iBmSycbmeTCSRNKJQ10EuA
更多推荐


所有评论(0)