请您用简单的英语向我解释一下XOR(^
)运算符及其在以下代码中的作用:
public int GetHashCode(Box bx)
{
int hCode = bx.Height ^ bx.Length ^ bx.Width;
return hCode.GetHashCode();
}
答案 0 :(得分:9)
XOR代表排他性或。它确保A或B是真的但不是两者都是。在这种情况下,我们进行按位操作,这样你就可以制作一个很好的结果图,它们如下;
0 ^ 1 = 1
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 0 = 0
由于您将其应用于整数,因此上述结果将应用于操作数中的每个位。因此,我们假设您分别为高度,长度和宽度设置了值1,2,3。
你会先
0001 ^ 0010导致0011然后将XOR' d变为3所以0011 ^ 0011为您提供0000
编辑:提供评论中的wiki链接以补充我的解释; http://en.wikipedia.org/wiki/Exclusive_or#Computer_science
编辑:为什么0001 ^ 0010
会导致0011
?
所以最好一点一点地做这件事。考虑运算符迭代两组位并比较它们的对。因此,在这种情况下,让我们从右到左工作(在这种情况下最不重要)。
1 ^ 0 = 1 // xxx1
0 ^ 1 = 1 // xx11
0 ^ 0 = 0 // x011
0 ^ 0 = 0 // 0011 - end of input
如此拼凑,你得到0011
。基本上,取每对输入并参考结果的真值表。注释显示x
的输出是尚未计算的值。
关于碰撞,是的,在这种情况下有很多碰撞。如果我说它是独特的,这是一个糟糕的词选择。我真正的意思是,如果你有2个,8个,4个作为你的值XOR' n它们按顺序总是会产生相同的值。
答案 1 :(得分:2)
稍微详细一点,您会在XOR
方法中看到很多getHashCode()
字段,因为它是获取对象签名的安全方式。签名的概念是它就像一个对象的指纹,它需要适合32位。许多对象使用此签名作为快速比较(但是,如果您计划使用它,请查看维基百科文章,因为您需要注意相等性和哈希码),或者某些一种寻址方式(如.net的Dictionary
和Java的HashMap
)。
我获得Box指纹的明显解决方案是简单地将值相加,这样如果其中任何一个改变,你将获得不同的指纹:
bx.Height + bx.Length + bx.Width
鉴于等于操作可能真的很贵(即非常慢),如果我们需要测试两个盒子的相等性:
Box {5, 10, 15}
Box {30, 40, 50}
我们可以比较两个哈希码,看看它们是不同的,并跳过完全相等的比较,而不是进行完全等于比较。在字典中,为我们提供一种快速查找 bin (元素)以放置对象的方法至关重要。
但是如果这些值中的任何一个太高,我们就会得到一个整数溢出异常,所以我们使用XOR而不是使用加法。另一个解决方案,也是C#相当独特的解决方案,是使用unchecked{ ... }
块,但使用XOR被认为更优雅。
我们可以做一件更微妙的事情来提高性能,你会看到很多自动生成的哈希码方法(比如ReSharper或IntelliJ产生的那些): 我们可以通过移动(乘以)每个值来使订单变得重要。
public int hashCode() {
int result = x;
result = 31 * result ^ y;
result = 31 * result ^ z;
return result;
}
现在发生的事情是,哈希码中的每个字段实际上都在最终的32位中占有一席之地。这意味着两个方框:
Box {1, 20, 30}
Box {1, 30, 20}
不会有相同的哈希码(它们与您当前的系统具有相同的哈希码,但它们是不同的!)
除了你想知道的有关哈希码的信息之外,我还会说一件事。
在Java / Scala和.net框架中,如果重载equals或hash-code,则必须也会使其他重载。 必须还要确保如果两个对象A和B具有不同的哈希码,则对A.Equals(B)的调用必须为false。