@erickson或多或少是正确的。返回的哈希码
java.lang.Object.hashCode()在对象的生存期内不变。
(通常)实现此方法的方式非常聪明。当对象由垃圾回收器重定位时,其原始哈希码必须存储在某个地方,以防再次使用。实现此目的的明显方法是将32位字段添加到对象标头中以保存哈希码。但这会给每个对象增加1个字的开销,并且在最常见的情况下会浪费空间…在这种情况下,
hashCode不会调用对象的方法。
解决方案是将两个标志位添加到对象的标志字中,并按如下方式(大致)使用它们。
hashCode调用方法时设置第一个标志。第二个标志告诉该
hashCode方法是使用对象的当前地址作为哈希码,还是使用存储的值。当GC运行并重定位对象时,它将测试这些标志。如果设置了第一个标志而未设置第二个标志,则GC在对象的末尾分配一个额外的单词,并将原始对象位置存储在该单词中。然后,它设置两个标志。从此以后,该
hashCode方法从对象末尾的单词获取哈希码值。
实际上,
identityHashCode实现 必须以这种方式
来满足常规hashCode合同的以下部分:
“只要在Java应用程序执行期间在同一对象上多次调用它,hashCode方法
就必须一致地返回相同的整数,只要没有修改该对象的equals比较中使用的信息即可 。一个应用程序的执行到同一应用程序的另一个执行。”
如果/当GC将对象移至其他地址时,假设的实现
identityHashCode()仅返回对象的 当前
机器地址将违反突出显示的部分。解决此问题的唯一方法是(假想的)JVM确保一旦
hashCode调用对象就永远不会移动它。这将导致堆碎片的严重而棘手的问题。



