/**
* 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);
}
任何人都可以详细解释这种方法,谢谢。
答案 0 :(得分:0)
设计通用哈希代码的一个问题是,你把所有这些努力都放在确保好的比特传播上,然后有人出现并以这样的方式使用它以完全撤消
让我们看一个带有X和Y两个整数的坐标类的经典例子。
这是一个经典的例子,因为人们会用它来证明X ^ Y
不是一个好的哈希码,因为它常见的是有几个对象,其中X == Y(所有哈希为0)或者其中一个X和Y是另一个的Y和X(将使用相同的哈希值)和其他我们最终使用相同哈希码的情况。
归结为这样一个事实:尽管整数的可能范围覆盖了40亿个值,但在99%的使用中,它们往往不到几百或几万。我们永远无法摆脱尝试在40亿个可能的结果中传播18亿可能的价值,但我们可以努力制作那些我们可能真正看到的,不太可能发生冲突。
现在,(X << 16 | X >> 16) ^ Y
在这种情况下做得更好,将X中的位分散开来。
不幸的是,如果使用此哈希是% someBinaryRoundNumer
来索引表(甚至% someOtherNumber
,稍微程度一点),那么对于低于{{1}的X值我们可以期待最常见的 - 这个哈希变得有效someBinaryRoundNumber
。
我们所有的辛勤工作都浪费了!
使用的rehash是使用这样的逻辑制作哈希,稍好一点。
值得注意的是,对return Y
方法过于批评是不公平的,因为哈希的另一种用法可以使这种形式优于给定的替代方案。
答案 1 :(得分:0)
不要进入细节,但是:
由于hascode()和equals()契约,哈希码函数的不良实现可能导致具有相同哈希码的不同实例。这意味着你可能有一个类具有糟糕的hashcode()方法实现,这样类的equals()方法将为A和B实例返回false(意味着它们与业务逻辑的观点不同)但hashcode()方法为实例A和B返回相同的值。同样,根据hashcode()和equals()契约,这在技术上是有效的,但不是很合适
在类似Hashtable的结构(如HashMap)中,“buckets”用于根据哈希码将实例放置在地图中。如果两个实例具有相同的hashcode()(但根据equas()方法不同),它们将被放置在同一个桶中。从性能的角度来看,这是不好的,因为当你遇到很多这样的情况时,你会失去一些类似Hashtable结构所固有的检索速度。被称为碰撞。发生的事情是,如果稍后某人使用“搜索”实例从哈希映射中检索某些内容,并且相应的哈希桶具有多个占用者,则必须使用equals()方法检查该桶中的每个元素以找出哪个是需要检索的那个。在极端情况下,可以将HashMap转换为这样的链接列表。
hash(int n)方法在现有的hashcode()值中添加了一些额外的东西,以便再次保护这种情况。