您能否用简单的英语解释一下 XOR ( ^
) 运算符是什么以及它在以下代码中的作用:
public int GetHashCode(Box bx)
{
int hCode = bx.Height ^ bx.Length ^ bx.Width;
return hCode.GetHashCode();
}
您能否用简单的英语解释一下 XOR ( ^
) 运算符是什么以及它在以下代码中的作用:
public int GetHashCode(Box bx)
{
int hCode = bx.Height ^ bx.Length ^ bx.Width;
return hCode.GetHashCode();
}
XOR 代表异或。它确保 A 或 B 中的任何一个都为真,但绝不是两者都为真。在这种情况下,我们正在执行按位运算,因此您可以制作一个漂亮的结果小图,它们如下所示;
0 ^ 1 = 1
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 0 = 0
由于您将其应用于整数,因此上述结果将应用于操作数中的每一位。因此,假设您的高度、长度和宽度分别为 1、2、3。
你首先会有
0001 ^ 0010 导致 0011 然后将异或成 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 它们按这个顺序总是会产生相同的值。
详细说明一下,您会XOR
在方法中的字段之间看到很多 ing,getHashCode()
因为它是获取对象签名的安全方法。签名的概念是它就像一个对象的指纹,它需要适合 32 位。此签名被许多对象用作快速比较,(但是,如果您打算为此使用它,请查看该维基百科文章,因为您需要注意相等性和哈希码),或者对于一些一种寻址方式(如 .netDictionary
和 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。