2012-09-03 60 views
10

有人可以解释这些常量的重要性以及为什么选择它们?计算java.util.hash的哈希码值时使用的常量说明

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

来源:java的SE6库

+1

没有重复,也不是答案,但你,如果你正在寻找这个东西可能会发现这个有趣的阅读:http://stackoverflow.com/questions/2538092/why-does-a-hashmap-rehash-在-哈希码提供的,由这关键对象 –

+4

[了解陌生的Java哈希函数(http://stackoverflow.com/questions/9335169/understanding-strange-java-hash-function)的可能重复 – jhurtado

+0

你是非常不可能在这个网站上得到这个问题的答案。最好的人来问将是'HashMap'类的设计者:Doug Lea的,乔希布洛赫,阿瑟·凡·霍夫,和Neal Gafter。尽管如果我不得不猜测我会说这些数字是凭经验确定的。 – Jeffrey

回答

0

我也想知道这种 “神奇” 的数字。据我所知他们的幻数。
通过广泛的测试已经证明,奇数和素数具有可用于哈希的有趣优先级(避免主/次集群等)。
我相信大部分数据都是经过研究和测试证明的,这些数据在统计学上证明分布很好。为什么专门这些数字做,我不知道,但在我的印象(希望的同事在这里可以纠正我,如果我的方式关闭)既不是实施者知道为什么这些具体数字呈现这些特质

2

了解什么使得一个好的散列函数是棘手的,因为实际上有很多不同的函数被使用,并且用途稍有不同。

Java的哈希表的工作方式如下:

  1. 他们问的关键对象产生它的散列码。 hashCode()方法的实现可能具有明显不同的质量(在最坏的情况下,返回一个恒定值!),并且绝对不会适应您正在使用的特定哈希表。
  2. 然后,他们使用上述函数将比特混合一位,以使高位中的信息也向下移动到低位。这是非常重要的,因为接下来...
  3. 它们采用散列码的模数(w.r.t.是散列表数组条目的数量)来获取散列表链数组中的索引。 哈希表阵列的大小相当于2的幂,所以第2步中的比特混合是非常重要的,以确保它们不会被丢弃。
  4. 然后他们遍历链,直到他们到达具有相同密钥的条目(根据equals()方法)。

要完成图片,散列表数组中的条目数是非常数的;如果链条变得太长,数组被替换为一个新的更大的数组,并且所有东西都被重新组合。这是相对较快的并且对于正常使用模式具有良好的性能影响(例如,大量的put()s,接着是大量的get()s)。

实际使用的常数是相当随意的(可能通过实验选择了一些简单的语料库,包括大量的IntegerString值),但其目的不是:将整个值中的信息传播到大部分该值中的低位确保尽可能好地使用存在于hashCode()的输出中的信息。 (你不会用完美的哈希算法或密码哈希算法来完成这项工作;尽管有相似的名字,但它们有着非常不同的实现策略,前者需要关键空间的知识以避免/减少碰撞,后者需要信息要在各个方向上移动,而不仅仅是低位。)