我的问题是:
哈希码的Object类默认实现是否使用identityhashcode?我认为是的。如果没有,请纠正我。
假设这是我的问题:假设一次调用hashCode()的对象在堆压缩期间被重定位(并与它一起存储identityhashcode),并且在第一个对象的旧位置创建了一个新的不同对象。在这种情况下,即使对象不同,两个对象的身份哈希码也将相同。如何解释呢?
最佳答案
据我了解,某些Java实现通过保留对象标头的两位来实现identityHashCode
,将对象分为三类:
从未调用过identityHashCode()
的那些。
第一次调用identityHashCode()
的事件发生在对象最近一次移动之后。
第一次调用identityHashCode()
的事件发生在对象最近一次移动之前。
对于第一类对象,对identityHashCode()
的调用将返回与该对象的地址相关的值,并设置一个标志以将该对象更改为第二类。对于第二个类别中的对象,identityHashCode()
将从地址中计算出与第一次调用相同的值。每当GC要移动对象时,它都会检查它是否在上面的第二类中。如果是这样,GC将在目标位置保留额外的四个字节,这些字节将用于保存对象在移动之前具有的标识哈希值。
如果对象采用其哈希码,则下次GC必须移动该对象时,该对象的有效大小将增加四个字节。大多数对象从不采用其身份哈希码,但是,有些对象却采用了其身份哈希码,但会立即被收集。第一次调用对象identityHashCode()
会为一个对象分配额外的四个字节很困难,但是在移动对象时分配额外的四个字节并不是问题。在第一次调用identityHashCode()
和下一次移动对象之间,使用对象的地址作为其哈希值可以避免在使用对象后面的空间时分配存储空间。
请注意,虽然身份哈希方法可以“合法”直接使用地址的位模式,但这样做可能会导致哈希重复次数过多(例如,在一个GC周期之后创建的第一个对象很容易具有与创建的第一个对象相同的地址一个接一个)。避免该问题的一种简单方法是让系统在每个GC周期后将地址加,异或以其他方式组合该值。这种方法将使散列值更容易地散布到更大的范围内。