就像 Jon Skeet in this SO answer 所描述的那样,最佳做法是选择一些素数并将它们与单个哈希码相乘,然后将所有内容相加。
public int GetHashCode()
{
unchecked
{
int hash = 17;
// Maybe nullity checks, if these are objects not primitives!
hash = hash * 23 + Zoom.GetHashCode();
hash = hash * 23 + X.GetHashCode();
hash = hash * 23 + Y.GetHashCode();
return hash;
}
}
xor 哈希的问题是:
- 如果
X 等于Y,那么你的哈希值就是Zoom,因为X ^ Y = X ^ X = 0 成立
-
xor 是一个对称运算符,它将为 [Zoom = 3, X = 5, Y = 7]、[Zoom = 3, X = 7, Y = 5]、[Zoom = 7, X = 5, Y = 3] 等对象生成完全相同的哈希。
这些事实使异或方法更容易引起冲突。
除了 Jons 的帖子,考虑使用 unchecked 上下文,以明确忽略溢出。因为就像MSDN 所说:
如果checked 和unchecked 都不是
使用时,常量表达式使用
编译时的默认溢出检查
时间,这是检查。否则,如果
表达式是非常数的,
运行时溢出检查取决于
其他因素,例如编译器选项
和环境配置。
因此,虽然通常不会检查溢出,但它可能会在某些环境中或使用某些编译器选项构建时失败。但在这种情况下,您希望明确不检查这些溢出。
更新:
顺便说一句:someInt.GetHashCode() 返回someInt。像这样,它当然是最快的和完美的哈希分布,没有一次碰撞。否则您将如何将 int 映射到 int-hash? :) 所以我想说的是:你的第一种方法:
return (Zoom + X + Y).GetHashCode();
还有你的第二个:
return Zoom.GetHashCode() + X.GetHashCode() + Y.GetHashCode();
完全一样。您甚至不必致电GetHashCode,两者都很可能发生冲突。可能比xor 方法更糟糕,如果您很可能对所有三个整数都有小整数值。
更新 2:
正如我在 ChaosPandions 帖子的评论中所写:如果您只有这三个 int 值,并且 X、Y 和 Zoom 是相对较小的数字(小于 1000 或 10000),这可能也是一个好的哈希生成器:
public int GetHashCode()
{
return (X << 16) ^ (Y << 8) ^ Zoom;
}
它只是分配散列值中的位(为了便于阅读,以 big-endian 为例):
00000000 00000000 00000011 00110001 X = 817
00000000 00000000 00011011 11111010 Y = 7162
00000000 00000000 00000010 10010110 Zoom = 662
00000011 00110001 00000000 00000000 X << 16
00000000 00011011 11111010 00000000 Y << 8
00000000 00000000 00000010 10010110 Zoom
00000011 00101010 11111000 10010110 (X << 16) ^ (Y << 8) ^ Zoom