HashMap中的哈希方法

可能重复:
HashMap#hash(int)方法的说明

/** * Applies a supplemental hash function to a given hashCode, which * defends against poor quality hash functions. This is critical * because HashMap uses power-of-two length hash tables, that * otherwise encounter collisions for hashCodes that do not differ * in lower bits. Note: Null keys always map to hash 0, thus index 0. */ static int hash(int h) { // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } 

任何人都可以详细解释这种方法,谢谢。

设计通用哈希码的一个问题是,你把所有这些努力都放在确保好的比特传播上,然后有人出现并以完全撤消它的方式使用它。

让我们来看一个带有X和Y两个整数的坐标类的经典例子。

这是一个典型的例子,因为人们会用它来certificateX ^ Y不是一个好的哈希码,因为它常见的是有几个对象,其中X == Y(所有哈希为0)或者其中X和Y是另一个的Y和X(将使用相同的哈希值)和其他我们最终使用相同哈希码的情况。

它归结为这样一个事实:虽然整数的可能范围覆盖了40亿个值,但在99%的使用中,它们往往不到几百或几万。 我们永远无法摆脱试图在40亿可能的结果中传播18亿可能的价值,但我们可以努力制造那些我们可能真正看到的,不太可能发生冲突。

现在, (X << 16 | X >> 16) ^ Y在这种情况下做得更好,从X传播比特更多。

不幸的是,如果使用这个哈希来做% someBinaryRoundNumer来索引到一个表(或者甚至% someOtherNumber ,到稍微程度),那么对于someBinaryRoundNumber值,我们可以期待最常见的someBinaryRoundNumber – 这个哈希变得有效return Y

我们所有的辛勤工作都浪费了!

使用的rehash是用这样的逻辑做一个哈希,稍好一点。

值得注意的是,过于批评(X << 16 | X >> 16) ^ Y方法是不公平的,因为哈希的另一种用法可以使该forms优于给定的替代方案。

好吧,不要进入细节,但:

  • 由于hascode()和equals()契约,哈希码函数的不良实现可能导致具有相同哈希码的不同实例。 这意味着你可能有一个类具有糟糕的hashcode()方法实现,这样类的equals()方法将为A和B实例返回false(意味着它们与业务逻辑的观点不同)但hashcode()方法为实例A和B返回相同的值。同样,根据hashcode()和equals()契约,这在技术上是有效的,但不是很合适

  • 在类似Hashtable的结构(如HashMap)中,“桶”用于根据哈希码将实例放置在地图内。 如果两个实例具有相同的哈希码()(但根据equas()方法不同),它们将被放置在同一个桶中。 从性能的角度来看,这是不好的,因为当你遇到很多这样的情况时,你会失去一些类似Hashtable结构所固有的检索速度。 被称为碰撞。 发生的事情是,如果稍后某人使用“搜索”实例从哈希映射中检索某些内容,并且相应的哈希桶具有多个占用者,则必须使用equals()方法检查该桶中的每个元素以找出哪个是需要检索的那个。 在极端情况下,可以将HashMap转换为这样的链接列表。

  • hash(int n)方法为现有的hashcode()值添加了一些额外的东西,以便再次保护这种情况。