为什么XOR经常用在java hashCode()中,但是另一个按位运算符很less被使用?
我经常看到类似的代码
int hashCode(){ return a^b; }
为什么是异或?
在所有比特操作中,XOR具有最好的比特混洗属性。
这个真值表解释了为什么:
AB AND 0 0 0 0 1 0 1 0 0 1 1 1 AB OR 0 0 0 0 1 1 1 0 1 1 1 1 AB XOR 0 0 0 0 1 1 1 0 1 1 1 0
正如你所看到的AND和OR在混合位上做的不好。
OR将平均产生3/4个一位。 另一方面将产生平均3/4的空位。 只有XOR具有一位与零位的分布。 这使得散列码生成非常有价值。
请记住,对于散列码,您希望尽可能多地使用关键字的信息,并获得散列值的良好分布。 如果你使用AND或者OR,你会得到一些数字,这些数字有很多零的数字或者有很多数字的数字。
异或具有以下优点:
- 它不依赖于计算的顺序,即a ^ b = b ^ a
- 它不会“浪费”位。 如果你改变一个组件中的一个位,最终的值将会改变。
- 即使是最原始的计算机上也是一个单一的循环。
- 它保持均匀分布。 如果你组合的两块是均匀分布的,那么组合就是这样。 换句话说,它并不倾向于把摘要的范围缩小到一个更窄的范围。
更多信息在这里 。
异或opertpr是可逆的,即假设我有一个位串作为0 0 1
并与另一个位串1 1 1
异或,输出是
0 xor 1 = 1 0 1 = 1 1 1 = 0
现在我可以agan异或第一个string的结果得到第二个string。 即
0 1 = 1 0 1 = 1 1 0 = 1
所以,这使得第二个string成为关键。 其他位操作符未find此行为
请参阅这个了解更多信息 – > 为什么在密码学上使用XOR?
还有另外一个用例: 其中(一些)字段必须与其顺序进行比较的对象。 例如,如果你想要一个对(a, b)
总是等于这个对(b, a)
。
XOR具有a ^ b
= b ^ a
,所以在这种情况下可以用在散列函数中。
例子:(完整的代码在这里 )
定义:
final class Connection { public final int A; public final int B; // some code omitted @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Connection that = (Connection) o; return (A == that.A && B == that.B || A == that.B && B == that.A); } @Override public int hashCode() { return A ^ B; } // some code omitted }
用法:
HashSet<Connection> s = new HashSet<>(); s.add(new Connection(1, 3)); s.add(new Connection(2, 3)); s.add(new Connection(3, 2)); s.add(new Connection(1, 3)); s.add(new Connection(2, 1)); s.remove(new Connection(1, 2)); for (Connection x : s) { System.out.println(x); } // output: // Connection{A=2, B=3} // Connection{A=1, B=3}