Object 类源码
概述
java.lang.Object 是所有 Java 类的基类。无论是自定义类还是 JDK 内建类,都直接或间接继承自 Object。Object 类定义了 11 个 native 方法以及若干关键的非 native 方法,构成了 Java 对象模型的基础设施。
本文逐方法拆解 Object 类的源码实现,重点关注 JVM 层面的 native 实现策略、并发原语的 ObjectMonitor 机制、以及各方法的子类重写模式。
本文基于 OpenJDK 21 源码分析,关键实现会对比不同 JVM 实现策略和 JDK 版本差异。
1. Object 的 11 个 native 方法
Object 类共声明了 11 个 native 方法,其中 registerNatives() 是静态的,其余均为实例方法:
// java.lang.Object(部分源码)
private static native void registerNatives();
public native int hashCode();
public final native Class<?> getClass();
protected native Object clone() throws CloneNotSupportedException;
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;
public final native void wait(long timeout, int nanos) throws InterruptedException;
// wait() 是非 native 的,委托给 wait(0)
public final void wait() throws InterruptedException {
wait(0L);
}
protected void finalize() throws Throwable { }注意:
wait(long, int)虽然是native方法,但纳秒精度实际由 HotSpot 实现决定——微秒以下通常不会精确等待。finalize()在 JDK 9+ 已被标记为@Deprecated(since="9")。
1.1 registerNatives() — 本地方法注册
private static native void registerNatives();registerNatives() 在 Object 类被加载时通过静态初始化块调用:
// java.lang.Object
private static native void registerNatives();
static {
registerNatives();
}JVM 层面的实现(HotSpot):
// hotspot/share/classfile/systemDictionary.cpp
// 当 JVM 加载 java.lang.Object 时,调用 Java_java_lang_Object_registerNatives()
JVM_ENTRY(void, JVM_RegisterNatives(JNIEnv *env, jclass cls, ...)) {
// 将 Object 的 native 方法映射到 JVM 内部的 JNI 函数指针
// 例如: hashCode → JVM_IHashCode()
// clone → JVM_Clone()
// wait → JVM_MonitorWait()
// notify → JVM_MonitorNotify()
}关键点:这些方法注册后,JVM 会直接调用对应的 C/C++ 实现,而非通过 JNI 的间接查找,从而获得极致性能。
2. hashCode() 的 JVM 实现策略
public native int hashCode();hashCode() 返回对象的哈希码,这是一个 int 值。其 native 实现在 HotSpot 中有多种策略,由 JVM 启动参数 -XX:hashCode=N 控制(N 的取值范围为 0-5):
| 策略值 | 名称 | 实现方式 |
|---|---|---|
| 0 | Park-Miller RNG | 使用随机数生成器,每调用一次生成一个新值 |
| 1 | 地址偏移 | object_addr ^ (object_addr >> 3) — 基于对象地址的偏移量 |
| 2 | 固定值 1 | 始终返回 1(性能最差,所有对象冲突) |
| 3 | 自增计数 | 从 0 开始,每调用一次自增 1 |
| 4 | 指针映射 | 将对象内存地址直接转换为 int |
| 5 | 随机数 | JDK 8+ 默认 — 线程本地随机数,第一次调用时生成并存入对象头 |
2.1 HotSpot 默认策略:hashCode == 5
// hotspot/share/runtime/synchronizer.cpp
static inline intptr_t get_next_hash(Thread *Self, oop obj) {
intptr_t value = 0;
if (hashCode == 0) { // Park-Miller RNG
value = os::random();
} else if (hashCode == 1) { // 地址偏移
value = (intptr_t(obj) ^ (intptr_t(obj) >> 3));
} else if (hashCode == 2) { // 固定 1
value = 1;
} else if (hashCode == 3) { // 自增
value = ++hashCounter;
} else if (hashCode == 4) { // 指针直接转换
value = (intptr_t)obj;
} else { // 默认 hashCode == 5: 线程本地随机数
unsigned t = Self->_hashState;
t ^= (t << 1);
Self->_hashState = t;
value = t;
}
return value;
}2.2 哈希码的存储与缓存
计算出的哈希码会被存入 对象头(Mark Word):
对象头 Mark Word 结构(64 位 JVM,未加锁时):
|-----------------------------------------------------------------------------------|
| unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 |
|-----------------------------------------------------------------------------------|hashCode()首次调用时计算,写入identity_hashcode字段- 之后再次调用直接返回缓存值,不会重复计算
- 一旦
identity_hashcode被写入,该对象的偏向锁就会被撤销(因为偏向锁需要复用 Mark Word 的位)
2.3 子类重写模式
// String 的 hashCode() 重写 — 按字符计算
public int hashCode() {
int h = hash; // 缓存,默认 0
if (h == 0 && !hashIsZero) {
h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
if (h == 0) {
hashIsZero = true;
} else {
hash = h;
}
}
return h;
}
// StringLatin1.hashCode(): 31 * h + (b[i] & 0xff)
// Integer 的 hashCode() — 直接返回值本身
public int hashCode() { return Integer.hashCode(value); }
public static int hashCode(int value) { return value; }关键规则:重写 hashCode() 必须同时重写 equals(),保证 a.equals(b) → a.hashCode() == b.hashCode()。
3. equals(Object) 的默认引用比较
public boolean equals(Object obj) {
return (this == obj);
}Object 的 equals() 使用 == 进行引用等价性比较——只有两个引用指向同一个对象时才返回 true。
3.1 子类重写模式
| 类 | 比较方式 | 实现要点 |
|---|---|---|
String | 字符数组逐元素比较 | 先比较引用 → 再比较长度 → 再 coder → 逐 byte 比较 |
Integer / Long | 包装值比较 | value == other.value |
List / Map | 元素逐一比较 | AbstractList.equals() 遍历迭代器 |
Arrays | 元素逐一比较 | Arrays.equals(array1, array2) 或 deepEquals() |
// String.equals() — 逐字符比较
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String aString) {
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}3.2 equals() 的 5 条合约约束
- 自反性:
x.equals(x)必须为true - 对称性:
x.equals(y) ⇔ y.equals(x) - 传递性:
x.equals(y) && y.equals(z) ⇒ x.equals(z) - 一致性:多次调用结果一致(对象未修改时)
- 非空性:
x.equals(null)必须为false
4. toString() 的默认实现
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}输出格式:{全限定类名}@{十六进制哈希码}
例如 new Object() 的 toString() 输出:
java.lang.Object@4eec7777子类重写示例:
| 类 | toString() 格式 |
|---|---|
String | 返回自身(this) |
Integer | String.valueOf(value) |
Arrays | Arrays.toString(arr) / Arrays.deepToString(arr) |
AbstractCollection | [elem1, elem2, ...] |
5. clone() 的浅拷贝机制
protected native Object clone() throws CloneNotSupportedException;clone() 是一个 protected native 方法,执行逐字段的浅拷贝。
5.1 HotSpot 实现
// hotspot/share/prims/jvm.cpp
JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle)) {
Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
// 检查是否实现了 Cloneable 接口
if (!obj->klass()->is_cloneable()) {
THROW_MSG_0(vmSymbols::java_lang_CloneNotSupportedException());
}
// 计算对象大小
const int size = obj->size();
// 分配新对象(浅拷贝:逐字复制)
oop new_obj = CollectedHeap::obj_allocate(klass, size, CHECK_NULL);
// 逐字复制:从源对象复制所有字段到目标对象
Copy::conjoint_jlongs_atomic(
(jlong*)obj(), (jlong*)new_obj,
(size_t)align_object_size(size) >> (LogBytesPerLong - LogHeapWordSize));
// 返回新对象
return JNIHandles::make_local(env, new_obj);
}5.2 浅拷贝示意图
克隆前: 克隆后:
┌──────────────┐ ┌──────────────┐
│ obj │ │ clone │
├──────────────┤ ├──────────────┤
│ int x = 10 │ (复制) │ int x = 10 │
│ String s ────┼──┐ │ String s ────┼──┐
└──────────────┘ │ └──────────────┘ │
▼ ▼
┌──────────┐ ┌──────────┐
│ "hello" │◄───────────────│ "hello" │
└──────────┘ (共享引用) └──────────┘- 基本类型字段:值被完整复制
- 引用类型字段:只复制引用,两个对象指向同一个实例
5.3 深度拷贝实现
若需深拷贝,必须重写 clone() 方法,手动复制引用类型的字段:
@Override
public Object clone() {
try {
Person cloned = (Person) super.clone(); // 先浅拷贝
cloned.addresses = new ArrayList<>(this.addresses); // 深拷贝集合
return cloned;
} catch (CloneNotSupportedException e) {
throw new AssertionError(e);
}
}6. finalize() 的 GC 回调
// JDK 9+ @Deprecated(since="9", forRemoval=true)
protected void finalize() throws Throwable { }finalize() 是 Object 的一个空方法,子类可重写以在 GC 前执行资源释放。但它已被 JDK 9 标记为废弃,不推荐使用。
6.1 Finalizer 机制的执行流程
对象不再可达
│
▼
GC 发现只有 Finalizer 引用可达
│
▼
JVM 将 Finalizer 加入 java.lang.ref.Finalizer.ReferenceQueue
│
▼
FinalizerThread 守护线程取出并调用 finalize()
│
▼
finalize() 执行完毕后清除引用,下次 GC 回收对象6.2 关键限制
| 限制 | 说明 |
|---|---|
| 仅执行一次 | finalize() 只会被调用一次,即使对象被"复活"后再次变为不可达 |
| 执行线程不可控 | 在 FinalizerThread(优先级第二高)上串行执行,可能阻塞 |
| 无法保证及时执行 | GC 时机不确定,finalize() 何时回调也不确定 |
| 性能开销大 | 重写 finalize() 的对象需要进入 Finalizer 链表,需要两次 GC 循环 |
// 不推荐:使用 finalize() 释放资源
public class Resource implements AutoCloseable {
private FileInputStream fis;
@Override
@Deprecated(since="9")
protected void finalize() throws Throwable {
fis.close(); // 不可靠!
}
}
// 推荐:使用 try-with-resources
try (Resource res = new Resource()) {
// 自动关闭
}6.3 替代方案
| 替代方案 | JDK 版本 | 说明 |
|---|---|---|
try-with-resources + AutoCloseable | JDK 7+ | 确定性资源释放,推荐首选 |
Cleaner(java.lang.ref.Cleaner) | JDK 9+ | 使用 PhantomReference 回调 Runnable,更可控 |
sun.misc.Cleaner | 内部 API | DirectByteBuffer 等内部使用 |
7. wait() / notify() / notifyAll() 的 ObjectMonitor 实现
这三个方法构成了 Java 的内建等待/通知机制,其底层基于 HotSpot 的 ObjectMonitor 实现。
7.1 方法签名
public final native void wait(long timeoutMillis) throws InterruptedException;
public final native void notify();
public final native void notifyAll();
// 非 native 包装
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) throw new IllegalArgumentException("timeout value is negative");
if (nanos < 0 || nanos > 999999) throw new IllegalArgumentException("...");
if (nanos > 0) timeout++; // 优化:纳秒非零则毫秒 +1(HotSpot 不保证微秒精度)
wait(timeout);
}
public final void wait() throws InterruptedException {
wait(0L); // 0 表示永久等待
}7.2 ObjectMonitor 的核心数据结构
ObjectMonitor 内部结构(简化):
┌─────────────────────────────────────────────┐
│ ObjectMonitor │
├─────────────────────────────────────────────┤
│ _owner → 持有锁的线程 │
│ _EntryList → 等待获取锁的线程队列 │
│ _WaitSet → 调用了 wait() 的线程队列 │
│ _recursions → 重入计数 │
│ _count → 锁计数 │
└─────────────────────────────────────────────┘7.3 wait() 的 HotSpot 实现
// hotspot/share/runtime/objectMonitor.cpp
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
Thread * const Self = THREAD;
// 1. 检查当前线程是否持有锁
if (Self != _owner) {
THROW_MSG(vmSymbols::java_lang_IllegalMonitorStateException());
}
// 2. 创建 WaitNode 并加入 _WaitSet
WaitNode node(Self);
add_to_wait_set(&node);
// 3. 释放锁(包括重入计数清零)
exit(true, Self);
// 4. 线程阻塞等待(使用 os::PlatformEvent::park)
// - timeout > 0: park(millis) 定时唤醒
// - timeout = 0: park() 永久等待
if (millis == 0) {
Self->_ParkEvent->park();
} else {
Self->_ParkEvent->park(millis);
}
// 5. 被唤醒后,重新竞争锁
// 从 _WaitSet 移除,加入 _EntryList 等待 _owner 释放锁
wait_reenter_end(Self, &node);
}7.4 notify() / notifyAll() 的 HotSpot 实现
void ObjectMonitor::notify(TRAPS) {
// 1. 检查线程是否持有锁
if (TPT != _owner) {
THROW_MSG(vmSymbols::java_lang_IllegalMonitorStateException());
}
// 2. 从 _WaitSet 中取出一个等待线程
WaitNode *iterator = DequeueWaiter();
if (iterator != NULL) {
// 3. 将该线程从 _WaitSet 移到 _EntryList
// 线程状态从 WAITING → BLOCKED
thread->set_pending_excitation(true);
// 4. 唤醒线程:unpark()
thread->_ParkEvent->unpark();
}
}
// notifyAll() 则遍历整个 _WaitSet,将全部等待线程移到 _EntryList
void ObjectMonitor::notifyAll(TRAPS) {
while (_WaitSet != NULL) {
notify(Self); // 逐个出队
}
}7.5 等待/通知的生命周期
Thread A Thread B
│ │
│ synchronized(obj) { │
│ obj.wait(); │
│ │ │ synchronized(obj) {
│ ▼ │ obj.notify();
│ ObjectMonitor.WaitSet │ │
│ (WAITING 状态) │ ▼
│ │ │ 从 WaitSet → EntryList
│ │ (被 unpark()) │ }
│ ▼ │
│ 重新竞争锁 │
│ ObjectMonitor.EntryList │
│ (BLOCKED 状态) │
│ │ │
│ ▼ │
│ 获取锁,wait() 返回 │
│ (RUNNABLE 状态) │
│ │ │7.6 wait(timeout) 的虚假唤醒
// 正确模式:必须在循环中检查等待条件
synchronized (lock) {
while (!condition) { // 不是 if!
lock.wait();
}
// 条件满足,继续执行
}这是因为 wait() 可能发生虚假唤醒(spurious wakeup)——线程在没有被 notify()、没有超时、也没有被中断的情况下被唤醒。这是操作系统的已知行为,必须在循环中重新检查条件。
8. getClass() 与 final 方法的设计意图
public final native Class<?> getClass();getClass() 被声明为 final,禁止子类重写。它返回对象的运行时类(Class 对象),这是 Java 反射系统的入口点。
Object obj = "hello";
Class<?> clazz = obj.getClass();
// clazz == java.lang.String.class
// 不是 java.lang.Object.class!8.1 getClass() vs 类字面常量
| 方式 | 返回 | 说明 |
|---|---|---|
obj.getClass() | 运行时实际类型 | final 方法,无法被覆盖 |
String.class | 编译期指定类型 | 类字面常量 |
Class.forName("java.lang.String") | 指定全限定名 | 反射方式 |
9. 方法汇总
| 方法 | 类型 | 作用 | 是否 native | 是否 final |
|---|---|---|---|---|
registerNatives() | static | 注册本地方法 | 是 | 否 |
hashCode() | instance | 返回哈希码 | 是 | 否 |
equals(Object) | instance | 比较相等 | 否 | 否 |
toString() | instance | 返回字符串表示 | 否 | 否 |
clone() | instance | 浅拷贝 | 是 | 否 |
getClass() | instance | 返回运行时类 | 是 | 是 |
notify() | instance | 唤醒一个等待线程 | 是 | 是 |
notifyAll() | instance | 唤醒所有等待线程 | 是 | 是 |
wait() | instance | 永久等待 | 否 | 是 |
wait(long) | instance | 超时等待 | 是 | 是 |
wait(long, int) | instance | 纳秒超时等待 | 是 | 是 |
finalize() | instance | GC 前回调 | 否 | 否 |
final 方法的设计意图:
getClass():防止子类篡改类型信息notify()/notifyAll()/wait():保证同步语义一致性,防止子类破坏锁协议
10. 关键类结构一览
java.lang.Object
├── native: registerNatives() ← 类加载时注册所有 native 方法
├── native: hashCode() ← Mark Word 缓存 + JVM 策略
├── native: getClass() ← final,返回运行时 Class 引用
├── native: clone() ← 浅拷贝,需实现 Cloneable
├── native: notify() ← ObjectMonitor._WaitSet
├── native: notifyAll() ← ObjectMonitor._WaitSet (全部)
├── native: wait(long) ← ObjectMonitor 释放锁 + park
├── wait(long, int) ← 纳秒优化:非零 +1ms
├── wait() ← wait(0L)
├── equals(Object) ← 引用比较 (this == obj)
├── toString() ← 类名@哈希码
└── finalize() ← @Deprecated(since="9")总结
- 11 个 native 方法构成了 JVM 对象模型的基础:对象创建(clone)、对象标识(hashCode/getClass)、同步(wait/notify)、生命周期(finalize)
- hashCode 的策略可配置:
-XX:hashCode=5(JDK 8+ 默认)使用线程本地随机数,计算结果缓存于对象头 - clone 是浅拷贝:JVM 层逐字复制对象内存,引用字段共享同一实例
- wait/notify 的底层是 ObjectMonitor:
_WaitSet存储等待线程,notify()将线程移到_EntryList重新竞争锁 - finalize 已废弃:由
Cleaner+PhantomReference替代,推荐使用try-with-resources