中 基础
Object类常用方法#
一句话答案#
核心方法:equals()(相等判断)、hashCode()(哈希值)、toString()(字符串表示)、clone()(浅拷贝)、wait/notify(线程通信)。
核心要点
关键方法:
equals():默认比较引用,重写比较内容hashCode():重写equals必须重写hashCodetoString():打印对象信息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 包含子类