HashMap中的哈希方法

时间:2012-08-29 10:36:13

标签: java

  

可能重复:
  Explanation of HashMap#hash(int) method

   /**
    * 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);
   }

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

2 个答案:

答案 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()值中添加了一些额外的东西,以便再次保护这种情况。