面试题 1:重载(Overload)与重写(Override)的底层本质区别是什么?
许多候选人只会说:
- “重载发生在同一个类中”
- “重写发生在父子类中”
这些都是表层定义,不能体现你的深度。
✅ 深度解读(面试官喜欢听的)
① 重载的本质是“编译期多态”
也叫 静态绑定(Static Binding)。
编译器根据方法参数列表决定调用哪个方法:
- 参数个数
- 参数类型
- 参数顺序
最终在 编译期就确定调用目标。
➡ JVM 根本不参与动态选择。
② 重写的本质是“运行期多态”
也叫 动态绑定(Dynamic Binding)。
运行时根据**实际对象类型(不是引用类型)**决定调用方法。
例如:
Father f = new Son();
f.print(); // 调用的是 Son 的实现
JVM 使用 虚方法表(vtable) 完成动态查找。
③ 两者在字节码上的本质差异
- 重载:字节码中生成 不同的方法签名(descriptor)
- 重写:子类覆盖父类方法,虚方法表(vtable)中的入口被替换
⭐ 面试官追问
- 构造方法能否重写?为什么?
- private 方法是否能重写?
- 静态方法为什么不能实现多态?
我可以帮你写第 1 篇的“追问扩展”版本,如果你需要。
❌ 易错点
- 以为返回值不同就能重载(不能!)
- private 方法表面上“继承”,实际上不参与多态
- 静态方法是“类绑定”,不走虚方法表
面试题 2:为什么必须同时重写 equals 和 hashCode?不重写会怎样?
这是 HashMap 相关面试的入门级关键题。
✅ 深度解读
① equals 是“逻辑相等”,hashCode 是“定位桶下标”
对于 HashMap 这样的容器,查找流程:
1. 用 hashCode() 计算桶位置
2. 再用 equals() 判断是否为目标 key
如果只重写 equals,不重写 hashCode:
👉 两个对象“逻辑相等”,但哈希值不同
👉 会被放到不同桶
👉 HashMap 永远找不到它
这是非常难排查的 bug。
② hashCode 的约定(必须遵守)
官方约定:
- 两个对象 equals 相等 → 必须拥有相同的 hashCode
- hashCode 相等,不要求 equals 相等
❗企业常问扩展
为什么不要求“hashCode 相同 → equals 一定相同”?
因为:
hash 碰撞是正常现象,将其强制唯一不现实,也不高效。
⭐ 面试官追问
- Hash 冲突越多会发生什么?
- 覆盖 equals 时忘记覆盖 hashCode,会有什么严重后果?
- 如何设计一个“好的 hashCode”?
❌ 易错点
- 错把 hashCode 当成“唯一标识”
- 用随机数实现 hashCode(极度错误)
- 以为 hash 冲突等于“性能很差”(1.8 已经优化为红黑树)
面试题 3:String 为什么不可变?底层如何实现?
这个题非常常考,但大多数候选人回答不到位。
⭐ ① 安全性考虑(核心原因)
String 常用于:
- 类加载
- 反射
- HashMap 的 key
- 网络参数
- 文件路径
如果可变,会带来严重安全问题:
String s = "abc";
s = "hack"; // 如果真的可变会导致系统被恶意利用
⭐ ② 缓存(String Pool)机制依赖不可变性
字符串常量池会缓存字符串引用,提升性能。
如果 String 可变:
- 修改一个实例,会影响所有引用它的地方
- 常量池彻底失效
⭐ ③ hashCode 缓存机制
String 的 hashCode 会被 缓存:
private int hash; // 默认 0,计算一次后缓存
如果可变,hashCode 不再稳定,HashMap 彻底乱套。
⭐ ④ 底层原理(你写付费内容的关键价值)
JDK 8:
private final char[] value;
JDK 9+ 采用 byte[] + coder 优化内存
仍然是 final,不可修改。
⭐ 面试官追问
- StringBuilder / StringBuffer 为什么可变?
- JDK 9 为什么要让 String 使用 byte[] 而不是 char[]?
- 字符串拼接 “+” 是如何优化的?
面试题 4:new String(“abc”) 会创建几个对象?
常见回答都是“1 个”或“2 个”,其实要看具体情况。
⭐ 正确答案(分场景):
① 第一次执行时:创建 2 个对象
String s = new String("abc");
- 常量池中创建
"abc" - 堆中创建一个 new String 实例,内部 value[] 复制自常量池
② 第二次执行时:创建 1 个对象
常量池已有 "abc",不会重复创建。
③ 关键点:字节码层面
字节码实际执行:
ldc "abc" → 放入常量池
new String → new 出对象
dup
invokespecial <init>
astore_1
所以准确说:
✔ 执行一次 new String(“abc”)
→ 至少 1 个对象(堆中)
→ 若常量池没值,则额外再创建 1 个
⭐ 面试官追问
- “abc” == new String(“abc”) 是 true 吗?
- intern() 方法有什么作用?
- String Pool 放在哪里(1.6 vs 1.8)?
面试题 5:Integer 缓存范围为什么是 [-128, 127]?能不能修改?
⭐ 深度解读
① 这个范围来自“最常用的整数区间”
Java 中最常出现的整数大部分都在 [-128,127],这是经验 + 实测数据得出的结论。
因此缓存该范围可以节省频繁 new Integer 的成本。
② IntegerCache 的底层实现
源码(精简):
private static class IntegerCache {
static final Integer cache[];
static {
for(int i = -128; i <= 127; i++)
cache[i + 128] = new Integer(i);
}
}
③ 可以修改缓存上限(你用以展示高级能力)
运行 JVM 时:
-XX:AutoBoxCacheMax=2000
即可将上限扩大到 2000。
这个细节面试官很喜欢。
⭐ 面试官追问
- Integer i1 = 127; Integer i2 = 127; 为什么 == 为 true?
- 那 i1 = 128; i2 = 128; 为什么不是同一个对象?
- 自动装箱和拆箱的底层是什么?
🟩 可打印总结(可当付费内容附赠 PDF)
第 1 篇核心知识点:
- 重载 = 编译期多态;重写 = 运行期多态(虚方法表)
- equals/hashCode 必须同时重写,否则 HashMap 查找失败
- String 不可变是为了安全性、常量池、hashCode 缓存
- new String(“abc”) 创建对象数量与常量池是否已有有关
- Integer 缓存范围 [-128,127],可通过 JVM 参数修改
这些题是企业 Java 基础考核的第一关。
15万+

被折叠的 条评论
为什么被折叠?



