通常,默认实现Object.hashCode()
是内存中对象的分配地址的某些功能(尽管JLS没有强制要求)。鉴于虚拟机在内存中分流对象,为什么System.identityHashCode()
在对象的生命周期内返回的值从不改变?
如果它是“一次性”计算(对象的hashCode
计算一次并隐藏在对象头或其他东西中),那么这是否意味着两个对象有可能具有相同的identityHashCode
(如果它们恰好在内存中的相同地址)?
通常,默认实现Object.hashCode()
是内存中对象的分配地址的某些功能(尽管JLS没有强制要求)。鉴于虚拟机在内存中分流对象,为什么System.identityHashCode()
在对象的生命周期内返回的值从不改变?
如果它是“一次性”计算(对象的hashCode
计算一次并隐藏在对象头或其他东西中),那么这是否意味着两个对象有可能具有相同的identityHashCode
(如果它们恰好在内存中的相同地址)?
现代 JVM 将值保存在对象标头中。我相信该值通常仅在首次使用时计算,以便将对象分配所花费的时间保持在最低限度(有时低至十几个周期)。可以编译通用的 Sun JVM,以便所有对象的标识哈希码始终为 1。
多个对象可以具有相同的身份哈希码。这就是哈希码的本质。
在回答第二个问题时,无论实现如何,多个对象都可能具有相同的 identityHashCode。
有关javadoc 中措辞的简要讨论,以及演示非唯一性的程序,请参见错误 6321873 。
HotSpot 中对象的头部由一个类指针和一个“标记”字组成。
标记词的数据结构的源代码可以在该markOop.hpp
文件中找到。在这个文件中,有一条注释描述了标记词的内存布局:
hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)
在这里我们可以看到,32 位系统上普通 Java 对象的身份哈希码保存在标记字中,长度为 25 位。
实现散列函数的一般准则是:
据我所知,这是为了返回引用而实现的,它在对象生命周期中永远不会改变。