"Object默认的hashCode()和内存地址有关"是一个流传很广、但真实不准确的说法。这篇真实用GC前后的对比,证明它虽然和身份相关,但真实不是内存地址本身。
上一篇:Collections.synchronizedList() 真实验证
用一个没有重写hashCode()的类,对比它的hashCode()和System.identityHashCode()的真实结果。
IdentityHashcodeDemo.java Plain p = new Plain(); // 没有重写hashCode() p.hashCode(); System.identityHashCode(p);
p.hashCode() 真实结果: 622488023 System.identityHashCode(p) 真实结果: 622488023 两者真实是否相等: true
真实结果证明了 Object.hashCode() 的默认实现真实就是 System.identityHashCode()——这是一个基于对象"身份"(而不是内容)计算出来的值,和 equals() 的默认实现(比较引用是否相同)在语义上是配套一致的。
如果这个值真的是内存地址,理论上垃圾回收器移动对象(如复制算法、压缩整理)之后,地址应该会变——真实测一下。
IdentityHashcodeDemo.java int hash1 = p.hashCode(); for (int i = 0; i < 5; i++) { System.gc(); Thread.sleep(50); } int hashAfterGc = p.hashCode();
真实触发多次GC... 多次GC后 p.hashCode() 真实结果: 622488023,是否和GC前相同: true
重写hashCode()的对象,o.hashCode() 真实结果: 42 同一个对象 System.identityHashCode(o) 真实结果: 1975012498 两者真实是否相等: false(应为false,identityHashCode真实不受重写影响)
真实结果证明 System.identityHashCode() 是一个真实独立的静态方法,不管这个对象的类是否重写了 hashCode(),它都真实绕过任何自定义逻辑,直接返回 JVM 层面的身份哈希值——这也是为什么它常被用在调试工具、序列化框架里需要真实追踪"这到底是不是同一个对象"的场景,不会被业务代码里的 hashCode() 重写干扰。
每一行都是真实运行这段代码得到的结果。