为啥 java hashCode() 中经常使用异或,而很少使用其他位运算符?
Posted
技术标签:
【中文标题】为啥 java hashCode() 中经常使用异或,而很少使用其他位运算符?【英文标题】:Why are XOR often used in java hashCode() but another bitwise operators are used rarely?为什么 java hashCode() 中经常使用异或,而很少使用其他位运算符? 【发布时间】:2011-01-21 00:15:20 【问题描述】:我经常看到类似的代码
int hashCode()
return a^b;
为什么要异或?
【问题讨论】:
可能重复 --> ***.com/questions/1379952/… 【参考方案1】:在所有位操作中,XOR 具有最好的位混洗特性。
这个真值表解释了原因:
A B AND
0 0 0
0 1 0
1 0 0
1 1 1
A B OR
0 0 0
0 1 1
1 0 1
1 1 1
A B XOR
0 0 0
0 1 1
1 0 1
1 1 0
正如您所见,AND 和 OR 在混合位方面做得很差。
OR 将平均产生 3/4 个一位。另一方面,AND 将平均产生 3/4 空位。只有 XOR 具有偶数位与空位分布。这使得它对于哈希码生成非常有价值。
请记住,对于散列码,您希望尽可能多地使用键信息并获得散列值的良好分布。如果你使用 AND 或 OR,你会得到偏向于有很多零的数字或有很多一的数字的数字。
【讨论】:
【参考方案2】:异或有以下优点:
它不依赖于计算顺序,即 a^b = b^a 它不会“浪费”位。如果您在其中一个组件中更改一点,最终值也会发生变化。 速度很快,即使在最原始的计算机上也只需一个周期。 它保持均匀分布。如果你组合的两部分是均匀分布的,那么组合也是如此。换句话说,它不会将摘要的范围压缩成更窄的范围。更多信息here.
【讨论】:
异或运算不会浪费位如果所有输入位都是独立的,但是如果它合并强相关的位,它可能会浪费很多。例如,如果一个类型表示 0-65535 范围内的一对数字,并通过将数字异或在一起形成哈希,则每个值中为零的高 16 位在哈希码中将为零。更糟糕的是,如果不成比例的实例数量(例如 10%)有两个数字匹配,那么相同比例的实例将返回零作为哈希值。【参考方案3】:XOR 运算符是可逆的,即假设我有一个位串为0 0 1
,我将它与另一个位串1 1 1
异或,输出为
0 xor 1 = 1
0 1 = 1
1 1 = 0
现在我可以再次将第一个字符串与结果进行异或,以获得第二个字符串。即
0 1 = 1
0 1 = 1
1 0 = 1
所以,这使第二个字符串成为键。其他位运算符未发现此行为
更多信息请看这里 --> Why is XOR used on Cryptography?
【讨论】:
hashCode 不需要倒置。 //对不起我的英语不好 是的,但 XOR 在密码学中的一种用途是其可逆性。【参考方案4】:还有另一个用例:对象必须在其中比较(某些)字段而不考虑它们的顺序。例如,如果您希望一对 (a, b)
始终等于一对 (b, a)
。
XOR 具有a ^ b
= b ^ a
的性质,所以在这种情况下可以用在哈希函数中。
示例:(完整代码here)
定义:
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:
// ConnectionA=2, B=3
// ConnectionA=1, B=3
【讨论】:
以上是关于为啥 java hashCode() 中经常使用异或,而很少使用其他位运算符?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在java的set集合中 hashcode相同 但equals结果可能为false
JAVA中重写equals方法为啥要重写hashcode方法说明
java 基础笔记--hashCode(),你好,为啥要重写