我正在为两个整数的简单容器对象重写equals和hashcode方法。每个int都反映了另一个对象的索引(该对象是什么并不重要)。该类的要点是表示两个对象之间的连接。
连接的方向无关紧要,因此无论两个整数在对象Eg中的哪个方向,等于方法都应该返回true。
connectionA = new Connection(1,2);
connectionB = new Connection(1,3);
connectionC = new Connection(2,1);
connectionA.equals(connectionB); // returns false
connectionA.equals(connectionC); // returns true
这是我所拥有的(从Integer的源代码修改):
public class Connection {
// Simple container for two numbers which are connected.
// Two Connection objects are equal regardless of the order of from and to.
int from;
int to;
public Connection(int from, int to) {
this.from = from;
this.to = to;
}
// Modifed from Integer source code
@Override
public boolean equals(Object obj) {
if (obj instanceof Connection) {
Connection connectionObj = (Connection) obj;
return ((from == connectionObj.from && to == connectionObj.to) || (from == connectionObj.to && to == connectionObj.from));
}
return false;
}
@Override
public int hashCode() {
return from*to;
}
}
这确实有效但我的问题是:有没有更好的方法来实现这个目标?
我主要担心的是hashcode()方法将为任意两个整数返回相同的哈希码,这两个整数相乘相同的数字。 E.g。
3*4 = 12
2*6 = 12 // same!
文档http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#hashCode()声明
如果两个对象根据不相等而不是必需的 equals(java.lang.Object)方法,然后调用hashCode方法 两个对象中的每一个都必须产生不同的整数结果。 但是,程序员应该意识到产生了不同的 不等对象的整数结果可以提高性能 哈希表。
如果有人能看到一种减少匹配哈希码数量的简单方法,那么我会很感激答案。
谢谢!
添
PS我知道有一个java.sql.Connection可能会导致一些导入烦恼。该对象实际上在我的应用程序中有一个更具体的名称,但为了简洁起见,我将其缩短为Connection here。
答案 0 :(得分:6)
已提出三种“有效”的解决方案。 (通过工作,我的意思是它们满足哈希码的基本要求......不同的输入提供不同的输出......并且它们还满足OP的额外“对称性”要求。)
这些是:
# 1
return from ^ to;
# 2
return to*to+from*from;
# 3
int res = 17;
res = res * 31 + Math.min(from, to);
res = res * 31 + Math.max(from, to);
return res;
第一个问题是输出范围受实际输入值范围的限制。因此,例如,如果我们假设输入分别是小于或等于2 i 和2 j 的非负数,那么输出将小于或等于2 MAX(I,J)。这可能会给你的哈希表中的“分散” 1 带来较差......并且碰撞率更高。 (from == to
时也有问题!)
第二个和第三个比第一个更好,但如果from
和to
很小,你仍然可能会遇到更多的碰撞。
如果最小化from
和to
的小值的冲突,我建议使用第4种替代方法。
#4
int res = Math.max(from, to);
res = (res << 16) | (res >>> 16); // exchange top and bottom 16 bits.
res = res ^ Math.min(from, to);
return res;
这样做的好处是,如果from
和to
都在0..2 16 -1范围内,则每个不同的(无序)都会得到一个唯一的哈希码)对。
1 - 我不知道这是否是正确的技术术语...
答案 1 :(得分:3)
这是一种被广泛接受的方法:
@Override
public int hashCode() {
int res = 17;
res = res * 31 + Math.min(from, to);
res = res * 31 + Math.max(from, to);
return res;
}
答案 2 :(得分:2)
我认为,像
@Override
public int hashCode() {
return to*to+from*from;
}
足够好
答案 3 :(得分:1)
通常我将XOR用于哈希码方法。
@Override
public int hashCode() {
return from ^ to;
}
答案 4 :(得分:0)
我想知道为什么没有人提供通常最好的解决方案:规范化您的数据:
Connection(int from, int to) {
this.from = Math.min(from, to);
this.to = Math.max(from, to);
}
如果不可能,那么我建议像
27644437 * (from+to) + Math.min(from, to)
使用奇数乘数确保乘法是双射的(即没有信息丢失)。
通过使用 prime ,你可以获得什么,但是每个人都这样做,并且它没有任何劣势。