1. 主页 > 小妙招

Java面试必问:Object类核心方法底层原理与高频考点

(拍大腿)哎我说!每次Java面试都逃不过Object类的灵魂拷问对吧?明明感觉会了,被面试官连环追问就支支吾吾?别慌!今天咱们把Object类扒得底裤都不剩,看完保你下次面试能跟面试官Battle三百回合!


一、为什么面试官总爱问Object类?

(抓头发)很多萌新想不通:这破类不就几个方法吗?有啥好问的?偷偷告诉你个行业秘密:??考察Object类就是检验Java基本功的试金石??!上个月我当技术面试官,10个候选人里8个说不清wait()和notify()为什么在Object里。你说该不该挂他们?

举个真实场景:

java复制
public class MyClass { 
    // 这里自动继承Object的11个方法
}

你造吗?就连空类都带着这11个"祖传方法",就像人生下来自带呼吸功能一样重要。现在知道为啥面试必考了吧?


二、getClass():类信息的时光胶囊

▍底层原理大揭秘

这个方法的实现其实是个本地方法:

java复制
public final native Class<?> getClass();

在HotSpot虚拟机里,每个对象头都存着指向类元数据的指针。说人话就是——对象身份证上的户籍地址!

▍高频考点三连杀:

  1. ??getClass()和instanceof有什么区别???
    • getClass()严格判断类型是否相同
    • instanceof考虑继承关系
  2. ??Class对象是单例吗???
    • 相同类加载器加载的同名类是同一个Class实例
  3. ??反射会触发类加载吗???
    • 调用getClass()不会,Class.forName()会!

(突然想到)等等,类加载器不同会导致getClass()返回不同结果吗?必须的啊!这可是实现热部署的关键原理!


三、hashCode():对象的内存身份证

▍默认实现有多魔幻?

在32位JVM中,默认返回的是对象头指针的后31位;64位JVM则会做异或运算压缩到31位。但别记这些数字!重点记住:

  • ??默认hashCode不等于内存地址??(虽然有关联)
  • ??对象移动(GC)后hashCode不变??(写屏障保证的)

▍夺命连环问:

  1. 两个对象hashCode相同,equals一定为true吗?
    • 错!哈希碰撞了解一下?
  2. System.identityHashCode()和hashCode()有什么区别?
    • 前者强制使用默认算法,后者可能被重写
  3. 为什么HashMap用(n-1)&hash计算索引?
    • 比取模运算快10倍以上!

四、equals():对象界的"大家来找茬"

▍方法契约三原则:

  1. 自反性:x.equals(x)必须true
  2. 对称性:x.equals(y) == y.equals(x)
  3. 传递性:x.equals(y)且y.equals(z),则x.equals(z)

(敲黑板)去年我们团队就因为违反对称性出过线上事故:新来的用instanceof判断,导致子类对象和父类对象比较结果不对称!

▍死亡陷阱题:

java复制
new BigDecimal("1.0").equals(new BigDecimal("1")) // 返回啥?

答案让人大跌眼镜——false!因为scale(小数位数)不同。所以BigDecimal比较要用compareTo()!


五、wait/notify:多线程界的牛郎织女

▍灵魂拷问:为什么在Object里?

因为Java的锁是对象级别的啊!每个对象都有个等待队列,就像医院候诊室:

  • wait():交出锁去候诊区排队
  • notify():护士叫下一个病人

▍血泪教训:

某金融系统曾因错误使用导致线程饿死:

java复制
synchronized(lock) {
    while(!condition) {
        lock.wait(); // 正确姿势
        // lock.wait(1000); 更好的选择
    }
}

要是用if代替while,遇到虚假唤醒就完犊子了!


六、clone():对象的复制术

▍深拷贝VS浅拷贝:

  • 浅拷贝:就像复印通讯录,号码还是同一个
  • 深拷贝:连对方手机都克隆一部新的

▍面试毒瘤题:

java复制
// 不实现Cloneable接口会怎样?
@Override
protected Object clone() throws CloneNotSupportedException { ... }

答案:运行时抛异常!这个设计被无数人吐槽——为啥不用编译时检查?Java设计者说这是历史遗留问题...


七、finalize():垃圾回收前的遗言

▍为什么被Java9标记为废弃?

  1. 执行时机不确定(可能永远不执行)
  2. 性能差(拖慢垃圾回收)
  3. 可能导致死锁(在finalize里搞事情)

替代方案直接用Cleaner类:

java复制
Cleaner.create(obj, () -> System.out.println("对象被回收啦!"));

说点得罪人的大实话

做了十年Java面试官,发现很多工作五年的老手,照样在Object类问题上翻车。比如上周面试个架构师,问他"为什么wait()需要放在同步块里",支支吾吾说"可能是规范要求"(笑cry)。

不过说真的,现在Java17都出了,很多新特性比如Record类、密封类,都在帮我们简化这些基础操作。但万变不离其宗,Object类的设计思想永远值得琢磨。下次面试再被问到,记得反问面试官:"您觉得Java设计者把wait()放在Object类合理吗?" 说不定能反客为主哦!

(突然拍脑袋)等等!你确定自己真的理解hashCode的生成规则了?赶紧打开IDE写个demo验证下,别被我的文章带沟里去了!

本文由嘻道妙招独家原创,未经允许,严禁转载