面试知识库
基础

Object类常用方法#

一句话答案#

核心方法:equals()(相等判断)、hashCode()(哈希值)、toString()(字符串表示)、clone()(浅拷贝)、wait/notify(线程通信)。

核心要点

关键方法:

  • equals():默认比较引用,重写比较内容
  • hashCode():重写equals必须重写hashCode
  • toString():打印对象信息
  • clone():浅拷贝(需实现Cloneable)
  • wait()/notify():线程间通信
  • getClass():获取运行时类型

clone() 的底层机制(深挖点):

  • protected native Object clone() —— 为什么是 native? 它不走任何 Java 构造逻辑,而是由 JVM 在堆上按对象内存布局逐字段拷贝(memcpy 式的内存复制),所以绕过构造方法:不调用 new、不执行构造器与实例初始化块。这也是它快、且能保留原对象瞬时状态的原因,但代价是构造方法里的不变式校验被跳过。
  • 因为按内存复制,引用字段只复制地址,所以默认是浅拷贝;要深拷贝得在重写的 clone() 里对引用字段再 clone() 一层。
  • Cloneable 为什么是”坏接口”(约书亚·布洛赫的经典批评): 它是个空标记接口(没有任何方法),却被 Object.clone() 用来做运行时判断——没实现它调用 clone() 就抛 CloneNotSupportedException。问题在于:真正的 clone 逻辑(protected native)定义在 Object 而非 Cloneable 上,二者靠隐式约定而非接口契约绑定;clone() 还是 protected,外部无法直接调,子类必须重写并提权为 public。整套设计让接口语义与实现脱节,故《Effective Java》建议改用拷贝构造器/拷贝工厂替代 Cloneable。
面试回答(2分钟版)

Object是所有Java类的根类,提供了几个非常核心的方法。equals和hashCode必须成对重写:equals默认比较引用地址,重写后按业务逻辑比较内容,同时必须重写hashCode保证equals相等的对象hashCode也相等,否则HashMap等哈希集合会出问题。toString默认返回类名加哈希值的十六进制,重写后便于调试打印对象信息。clone方法执行的是浅拷贝,只复制基本类型和引用地址,引用对象本身不会被克隆,使用前必须实现Cloneable接口否则抛CloneNotSupportedException。wait和notify是线程间通信的基础方法,必须在synchronized块中调用,因为它们依赖对象的Monitor锁——wait释放锁并进入等待队列,notify唤醒一个等待线程。wait必须在synchronized中是为了防止lost wake-up问题。getClass返回运行时的实际类型,和instanceof的区别是getClass精确匹配不考虑子类。finalize已在JDK9废弃,因为执行时机不确定且影响GC性能,资源释放应该用try-with-resources。

追问与易错

追问方向:

  • “clone() 是深拷贝还是浅拷贝?”→ 默认是浅拷贝,只复制基本类型值和引用地址,引用对象本身不会被克隆;需实现 Cloneable 接口否则抛 CloneNotSupportedException
  • “finalize() 为什么不推荐用?”→ 执行时机不确定(GC 何时回收不可控)、影响 GC 性能(需两次标记)、JDK9 已标记 @Deprecated,资源释放应用 try-with-resources 或 Cleaner
  • “wait() 为什么必须在 synchronized 中?”→ 防止 lost wake-up 问题:如果不加锁,notify 可能在 wait 之前执行导致信号丢失,线程永远等待;wait 会释放持有的 Monitor 锁

易错点:

  • ❌ ”== 和 equals 对所有对象行为一样”——Object 默认 equals 就是 ==,需要重写
  • ❌ 忘记 getClass() 和 instanceof 的区别——getClass 精确匹配,instanceof 包含子类