System.identityHashCode(Object x)
是 Java 中用于获取对象身份哈希码(Identity Hash Code)的静态方法。它与 Object.hashCode()
不同,不会被对象重写所影响,始终返回基于对象内存地址(或等效机制)的哈希值,是判断对象物理唯一性的重要工具。
一、方法定义
public static int identityHashCode(Object x)
- 所属类:
java.lang.System
- 访问修饰符:
public static
- 参数:
x
(Object
):要获取哈希码的对象
- 返回值:
- 返回对象的“身份哈希码”(
int
类型) - 如果
x
为null
,返回0
- 返回对象的“身份哈希码”(
- 异常:无
🔗 关联方法:
Object.hashCode()
:可被重写,逻辑哈希码Objects.hashCode(Object)
:空安全的hashCode()
调用
二、功能说明
System.identityHashCode()
的核心功能是:
- 获取对象的“身份”哈希码,该值:
- 基于对象的内存地址(JVM 实现相关)
- 在对象生命周期内通常保持不变
- 不会被
Object.hashCode()
的重写所影响
- 用于判断两个引用是否指向同一个对象实例(物理相等性)
✅ 典型用途:
- 调试时区分对象实例
- 实现自定义哈希结构(如基于引用的缓存)
- 检测
hashCode()
是否被重写- 理解 JVM 对象标识机制
三、示例代码
1. 基本使用:获取对象身份哈希码
public class IdentityHashCodeExample {
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
// String 重写了 hashCode(),内容相同则哈希码相同
System.out.println("s1.hashCode(): " + s1.hashCode()); // 例如: 99162322
System.out.println("s2.hashCode(): " + s2.hashCode()); // 相同: 99162322
// identityHashCode 基于对象实例,不同实例不同
System.out.println("System.identityHashCode(s1): " + System.identityHashCode(s1)); // 例如: 12345678
System.out.println("System.identityHashCode(s2): " + System.identityHashCode(s2)); // 不同: 87654321
}
}
2. 与 ==
操作符配合使用
public class CompareWithIdentity {
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = new Object();
Object obj3 = obj1;
System.out.println("obj1 == obj2 ? " + (obj1 == obj2)); // false
System.out.println("identityHashCode 相同? " +
(System.identityHashCode(obj1) == System.identityHashCode(obj2))); // false
System.out.println("obj1 == obj3 ? " + (obj1 == obj3)); // true
System.out.println("identityHashCode 相同? " +
(System.identityHashCode(obj1) == System.identityHashCode(obj3))); // true
}
}
3. 处理 null
值
public class NullHandling {
public static void main(String[] args) {
Object obj = null;
int hash = System.identityHashCode(obj);
System.out.println("null 的 identityHashCode: " + hash); // 输出: 0
}
}
4. 检测 hashCode()
是否被重写
class PlainObject {
// 未重写 hashCode()
}
class CustomHashObject {
@Override
public int hashCode() {
return 42; // 固定返回 42
}
}
public class HashOverrideCheck {
public static void main(String[] args) {
PlainObject p1 = new PlainObject();
PlainObject p2 = new PlainObject();
System.out.println("PlainObject hashCode(): " + p1.hashCode());
System.out.println("identityHashCode: " + System.identityHashCode(p1));
// 通常 hashCode() == identityHashCode() 对于未重写的类
CustomHashObject c1 = new CustomHashObject();
CustomHashObject c2 = new CustomHashObject();
System.out.println("CustomHashObject hashCode(): " + c1.hashCode()); // 42
System.out.println("identityHashCode: " + System.identityHashCode(c1)); // 不同于 42
System.out.println("c1 和 c2 identityHashCode 相同? " +
(System.identityHashCode(c1) == System.identityHashCode(c2))); // false
}
}
四、使用技巧
调试时打印对象唯一标识:
System.out.println("对象: " + obj + " [ID Hash: " + System.identityHashCode(obj) + "]");
实现基于引用的缓存(Reference-based Cache):
// 使用 identityHashCode + == 判断 key Map<Object, String> cache = new java.util.WeakHashMap<>(); // WeakHashMap 使用 identityHashCode
生成对象唯一 ID(临时):
String objectId = Integer.toHexString(System.identityHashCode(obj));
与
toString()
结合:// Object.toString() 默认使用 identityHashCode System.out.println(obj); // 输出: 类名@十六进制哈希码
五、常见错误
错误 | 原因 | 解决方案 |
---|---|---|
误认为 identityHashCode 唯一 |
哈希码可能冲突(int 范围有限) | 配合 == 使用,不能仅靠哈希码判断相等 |
误用于集合的 hashCode |
集合依赖 Object.hashCode() |
如需基于引用的哈希,使用 IdentityHashMap |
认为哈希码永不变化 | JVM 可能移动对象(GC) | 现代 JVM 通过对象头存储,通常不变,但不绝对保证 |
六、注意事项
不是真正的内存地址:
- 返回值不是直接的内存地址,而是基于地址生成的哈希码。
- JVM 实现可能使用对象头中的“mark word”存储。
哈希码可能重复:
int
范围有限(约 42 亿),大量对象可能哈希冲突。- 必须配合
==
进行精确判断。
与
equals()
和hashCode()
的关系:identityHashCode
与equals()
无关。- 它提供的是“物理相等性”,而
equals()
是“逻辑相等性”。
性能:
- 调用开销极低,通常是本地方法(native)。
多线程安全:
- 方法本身线程安全,但对象状态可能变化。
七、最佳实践与性能优化
✅ 最佳实践
用于调试和日志:
- 在日志中输出对象的
identityHashCode
,便于追踪对象生命周期。
- 在日志中输出对象的
实现
IdentityHashMap
语义:- 当需要基于引用(而非
equals
)进行映射时,使用java.util.IdentityHashMap
,它内部使用System.identityHashCode()
。
- 当需要基于引用(而非
避免在业务逻辑中依赖:
- 业务逻辑应基于
equals()
和hashCode()
,而非身份哈希码。
- 业务逻辑应基于
理解其与
toString()
的关系:Object.toString()
默认实现为:getClass().getName() + '@' + Integer.toHexString(hashCode())
- 此处的
hashCode()
实际上是identityHashCode()
(对于未重写的类)。
🚫 反模式(避免)
// 错误:仅用 identityHashCode 判断对象相等
if (System.identityHashCode(a) == System.identityHashCode(b)) {
// ❌ 可能哈希冲突,a 和 b 可能是不同对象
}
// 正确:配合 == 使用
if (a == b) { // 或 System.identityHashCode(a) == System.identityHashCode(b) && a == b
// ✅ 安全
}
性能优化
System.identityHashCode()
本身性能极高,无需优化。- 关键在于使用场景:
- 频繁调用无性能问题。
- 避免在循环中重复调用(可缓存结果):
int hash = System.identityHashCode(obj); for (int i = 0; i < 1000; i++) { // 使用 hash,而非重复调用 identityHashCode }
八、identityHashCode
vs hashCode()
对比总结
特性 | System.identityHashCode(Object) |
Object.hashCode() |
---|---|---|
是否可被重写 | ❌ 否,始终返回身份码 | ✅ 是,可被类重写 |
基础 | 对象的物理标识(内存地址等) | 对象的逻辑状态(如内容) |
String "hello" 两个实例 |
不同 | 相同(内容相同) |
null 值 |
返回 0 |
调用会抛 NullPointerException |
用途 | 判断对象实例唯一性、调试 | 集合哈希存储、逻辑相等性 |
典型应用 | IdentityHashMap , 调试 |
HashMap , HashSet |
九、总结
System.identityHashCode(Object x)
是 Java 中用于获取对象身份标识的底层工具,它提供了不被重写的、基于对象物理存在的哈希码。
💡 一句话总结:
System.identityHashCode()
是对象的“身份证号”,而Object.hashCode()
是对象的“名字”。
当你需要知道“是不是同一个对象”,而不是“内容是否相同”时,使用identityHashCode
。