System.identityHashCode(obj) 返回对象创建时写入对象头的固定身份哈希值,不受类中hashCode()重写影响;它反映对象物理同一性而非逻辑内容,null返回0,同一对象多次调用结果恒定。

直接调用 System.identityHashCode(obj) 就能拿到对象的原始身份哈希值,完全绕过类中重写的 hashCode() 方法。它不看业务逻辑,只认 JVM 分配给这个对象的“身份证号”。
它为什么不受重写影响
因为 identityHashCode 是 JVM 在对象创建时就写入对象头(如 mark word)的一个固定整数,和内存地址弱相关但稳定不变。而 obj.hashCode() 是运行时动态查找并调用该对象所属类的方法——如果类重写了它,就执行重写逻辑;没重写才退回到 Object 默认实现,后者底层才可能等价于 identityHashCode。
- String、ArrayList、自定义类……无论是否重写
hashCode(),System.identityHashCode()结果始终反映对象本身,不是内容 - null 调用返回 0,使用前建议判空
- 同一对象在 JVM 生命周期内,多次调用结果一定相同(即使字段变了、GC 移动了位置)
典型使用场景
当你需要区分“逻辑相等”和“物理同一”时,identityHashCode 就是关键工具:
- 调试时快速判断两个对象是不是同一个实例(比如监听器重复注册、集合里存的是副本还是引用)
- 实现基于引用而非内容的缓存或映射结构(
IdentityHashMap内部正是靠它 +==判断键) - 序列化/反序列化后验证对象是否被重建(新对象的 identityHashCode 必然不同)
- 单元测试中验证“不是同一个实例”,又不方便直接用
==(例如被封装在不同 wrapper 中)
常见误区与注意事项
它不是内存地址,也不能当指针用:
- 不能用于 Unsafe 操作、JNI 地址传递或内存寻址——这是最危险的误用
- 返回值是
int,存在哈希冲突可能(不同对象偶然相同),所以仅靠它不能断言“是同一对象”,必须配合==验证 - 对象被 GC 回收后,其 identityHashCode 可能被复用给新对象,绝不能跨 GC 周期持久化存储做比较
- 数组也支持:
System.identityHashCode(new int[5])返回的是数组对象的身份码,和元素无关
和普通 hashCode() 的直观对比
看这段代码就清楚了:
String a = new String("hello");
String b = new String("hello");
System.out.println(a.equals(b)); // true
System.out.println(a.hashCode() == b.hashCode()); // true(String 重写了)
System.out.println(System.identityHashCode(a) == System.identityHashCode(b)); // false(确实是两个对象)

















