第 1 篇:Java 核心基础(深度解析 5 题)

面试题 1:重载(Overload)与重写(Override)的底层本质区别是什么?

许多候选人只会说:

  • “重载发生在同一个类中”
  • “重写发生在父子类中”

这些都是表层定义,不能体现你的深度。


深度解读(面试官喜欢听的)

① 重载的本质是“编译期多态”

也叫 静态绑定(Static Binding)。

编译器根据方法参数列表决定调用哪个方法:

  • 参数个数
  • 参数类型
  • 参数顺序

最终在 编译期就确定调用目标

JVM 根本不参与动态选择。


② 重写的本质是“运行期多态”

也叫 动态绑定(Dynamic Binding)。

运行时根据**实际对象类型(不是引用类型)**决定调用方法。

例如:

Father f = new Son();
f.print(); // 调用的是 Son 的实现

JVM 使用 虚方法表(vtable) 完成动态查找。


③ 两者在字节码上的本质差异

  • 重载:字节码中生成 不同的方法签名(descriptor)
  • 重写:子类覆盖父类方法,虚方法表(vtable)中的入口被替换

⭐ 面试官追问

  1. 构造方法能否重写?为什么?
  2. private 方法是否能重写?
  3. 静态方法为什么不能实现多态?

我可以帮你写第 1 篇的“追问扩展”版本,如果你需要。


❌ 易错点

  • 以为返回值不同就能重载(不能!)
  • private 方法表面上“继承”,实际上不参与多态
  • 静态方法是“类绑定”,不走虚方法表


面试题 2:为什么必须同时重写 equals 和 hashCode?不重写会怎样?

这是 HashMap 相关面试的入门级关键题。


✅ 深度解读

① equals 是“逻辑相等”,hashCode 是“定位桶下标”

对于 HashMap 这样的容器,查找流程:

1. 用 hashCode() 计算桶位置
2. 再用 equals() 判断是否为目标 key

如果只重写 equals,不重写 hashCode:

👉 两个对象“逻辑相等”,但哈希值不同
👉 会被放到不同桶
👉 HashMap 永远找不到它

这是非常难排查的 bug。


② hashCode 的约定(必须遵守)

官方约定:

  1. 两个对象 equals 相等 → 必须拥有相同的 hashCode
  2. hashCode 相等,不要求 equals 相等

❗企业常问扩展

为什么不要求“hashCode 相同 → equals 一定相同”?

因为:
hash 碰撞是正常现象,将其强制唯一不现实,也不高效。


⭐ 面试官追问

  1. Hash 冲突越多会发生什么?
  2. 覆盖 equals 时忘记覆盖 hashCode,会有什么严重后果?
  3. 如何设计一个“好的 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,不可修改。


⭐ 面试官追问

  1. StringBuilder / StringBuffer 为什么可变?
  2. JDK 9 为什么要让 String 使用 byte[] 而不是 char[]?
  3. 字符串拼接 “+” 是如何优化的?


面试题 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 个


⭐ 面试官追问

  1. “abc” == new String(“abc”) 是 true 吗?
  2. intern() 方法有什么作用?
  3. 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。

这个细节面试官很喜欢。


⭐ 面试官追问

  1. Integer i1 = 127; Integer i2 = 127; 为什么 == 为 true?
  2. 那 i1 = 128; i2 = 128; 为什么不是同一个对象?
  3. 自动装箱和拆箱的底层是什么?


🟩 可打印总结(可当付费内容附赠 PDF)

第 1 篇核心知识点:

  • 重载 = 编译期多态;重写 = 运行期多态(虚方法表)
  • equals/hashCode 必须同时重写,否则 HashMap 查找失败
  • String 不可变是为了安全性、常量池、hashCode 缓存
  • new String(“abc”) 创建对象数量与常量池是否已有有关
  • Integer 缓存范围 [-128,127],可通过 JVM 参数修改

这些题是企业 Java 基础考核的第一关。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愤怒的代码

如果您有受益,欢迎打赏博主😊

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值