(l >> 32) ^ l
在大多数情况下是一个很好的哈希码;特别是当 long 具有均匀分布时。
由于它是被接受的答案,我在此发布这篇文章,以澄清我的一些评论,即在某些情况下,它不是一个很好的 long 类型的哈希码。
我给出的例子是一个像这样的 Point 类:
public class Point {
private final long coords;
public int getX() {
return (int)(coords >> 32);
}
public int getY() {
return (int)coords;
}
public int hashCode() {
return (int)((coords >> 32) ^ (coords));
}
}
看起来有些牵强,但有时您会将多个“字段”打包到一个长字段中。
因此,coords
字段表示32位x和32位y。那么这是个问题吗?如果每个x和y在各自的32位上均匀分布,那么就不是问题。但在实践中,这是不太可能的。更有可能的情况是X和Y受到某个数字的限制。假设为1024,因为它是2^10。这意味着最多设置每个X和Y的低10位:
00000000 00000000 000000XX XXXXXXXX 00000000 00000000 000000YY YYYYYYYY
有2^20(1024 * 1024)种可能的组合。但是hashCode方法在做什么呢?
00000000 00000000 000000XX XXXXXXXX
^ 00000000 00000000 000000YY YYYYYYYY
= 00000000 00000000 000000?? ????????
由于只有低10位可以是非零值,因此最多可能有2^10(1024)个hashCode值。哈希值与实际值的比率为1024:(1024*1024)
或1:1024
。因此,一开始就有1/1024的概率两个数字具有相同的哈希值。
现在让我们通过应用birthday problem中的数学来计算碰撞的概率。设p(n)为n个值中至少会有一个碰撞的概率。我们知道p(1025+) = 1,因为只有1024个值。
p(n) = 1 - (n! * (1024 choose n))/1024^n
这可以转化为以下内容:
n: p(n)
1: 0.00000
2: 0.00098
3: 0.00293
4: 0.00585
5: 0.00973
6: 0.01457
...
38: 0.50096
...
79: 0.95444
...
148: 0.99999
仅有38个项目,很可能会发生碰撞。有148个项目时,至少有99.999%的概率会发生碰撞。在148个项目中,每个项目与另一个项目发生碰撞的概率为7%。通过正确的哈希函数,结合对领域的了解,这些数字可以轻松降至0。
换句话说,了解您的领域以及实践中发生的事情是制作高性能哈希的关键。库函数尝试尽可能做到不了解您的领域,并且为了性能通常依赖于在实践中不会出现的数据分布。
int hashCode = (int) id
。 - GrodriguezLong.hashcode(long)
不会在堆栈上创建新对象。 - Neuron(this.longValue()^(this.longValue()>>>32))
能产生比仅保留该值的低32位更均匀分布的哈希码。 - GrodriguezInteger.MAX_VALUE
或MIN_VALUE
,这正是我所期望的强制转换实际上要做的事情。 - Neuron