当 equals() 基于多个独立字段时的 hashCode() 方法
题
我有一个类,其相等性基于两个字段,如果其中一个字段相等,则该类型的对象被视为相等。我如何为这样的 equals() 编写 hashCode() 函数,以便保留当 equals 返回 true 时 hashCode 相等的一般契约?
public class MyClass {
int id;
String name;
public boolean equals(Object o) {
if (!(o instanceof MyClass))
return false;
MyClass other = (MyClass) o;
if (other.id == this.id || other.name == this.name)
return true;
return false;
}
}
我如何为此类编写 hashCode() 函数?我想避免这里返回常量的小情况,如下所示:
public int hashCode() {
return 1;
}
其他提示
确定,在方案中,忽略用于第二API的要求,也没有非恒定散列函数
想象有这对于具有不同值的散列函数
(A,B),(A,C)中,b!= C,则散列(A,B)!=散列(A,C)沉绵(A,B)=(A,C)。
类似地,(B,A)和(C,A)必须发射相同哈希码。
让我们把我们的哈希函数h。我们发现:
H(X,Y)= H(X,W)= H(V,W)的forall X,Y,V,W
因此,那你想要做什么的唯一散列函数是恒定的。
我敢肯定,扎克的权利 - 有没有非平凡的哈希码做
伪证明:
考虑任何两个不相等的值,X =(ID1,NAME1)和Y =(ID2,NAME2)。
现在考虑Z =(ID2,NAME1)。这是等于X和Y,所以必须具有相同的散列码既是X和Y.因此X和Y必须具有相同的散列码。 - 这意味着所有的值必须具有相同的散列码
有一个原因,你已经陷入了奇怪的情况 - 你打破平等的传递性质。事实上,X.equals(Z)和Z.equals(Y)的应的意思是X.equals(Y) - 但事实并非如此。您的平等的定义是不适合的equals的正常合同。
我觉得你不能。其原因是,你的equals()
方法没有传递的。
及物装置,用于三个非零的X,Y,Z,如果x.equals(y)
,y.equals(z)
,然后x.equals(z)
。在你的榜样,对象x={id: 1, name: "ha"}
,y={id: 1, name: "foo"}
,z={id: 2, name: "bar"}
具有这种性质的(x.equals(y) and y.equals(z))
。然而,x.equals(z)
是false
。每个equals()
方法应该有这个特性,请参阅Java API文档。
返回散列函数:每个函数产生由f(x)==f(y)
确定的等价。这意味着,如果你有兴趣的函数值的比较,并希望它返回true,如果x==y
(也可能在其他情况下),你会收到一个传递关系,这意味着你必须要考虑至少对象的传递闭包等价。在你的情况,传递闭包是微不足道的关系(一切等于什么)。这意味着可以不被任何功能区分不同的对象。
您是否有意定义为平等时,ID是相等或名称相同..不如果是“或”是“和”?
如果你的意思是“AND”,那么你的哈希码应该用计算非常相同或更小(但从未使用不使用等号字段)字段,你是通过equals()方法。
如果你的意思是“OR”,那么[R hashgcode不应该包含的ID或名称在其哈希码计算其并没有真正意义。
编辑:我没有仔细阅读问题
。-
我将使用公共资源浪广口瓶中。
XOR成员的hashCode应的作品。因为他们应该实现hashCode()和equals()方法正确。
然而,你的代码可能会错的,如果你不保护你的hashCode。 一旦它被散列,它不应该被改变。它应被发生来防止。
public hashCode(){
return new AssertionError();
}
或
public class MyClass {
final int id;
final String name;
// constructor
}
或
public class MyClass {
private int id;
private String name;
boolean hashed=false;
public void setId(int value){
if(hashed)throw new IllegalStateException();
this.id=value;
}
public void setName(String value){
if(hashed)throw new IllegalStateException();
this.name=value;
}
// your equals() here
public hashCode(){
hashed=true;
return new HashCodeBuilder().append(id).append(name).toHashCode();
}
}
在重新读取的问题。
您可以自动完成,当他们中的一个被更新的另一个领域。
-
编辑:我的代码可以说更好,然后我的英语
。void setName(String value){
this.id=Lookup.IDbyName(value);
}
void setID(String value){
this.name=Lookup.NamebyId(value);
}
编辑2:
这是问题的代码可能错了,因为总会除非你同时设置ID和名称返回true。
如果你真的想要做的那个部分的equals方法,创建自己的名为API“partialEquals()”。
最简单的途径是XOR每个单独的字段的散列码。这在某些情况下,轻微的丑陋(例如,在X,Y坐标,它会导致有当你翻转X和Y等于散列的可能不好的情况),但总体是非常有效的。 TWEAK根据需要,以减少在必要时对碰撞效率。
这个怎么样
public override int GetHashCode()
{
return (id.ToString() + name.ToString()).GetHashCode();
}
该函数应返回永诺一个“有效”散列...
编辑:只注意到你用“或”不是“和”:P好吧,我怀疑有什么好的办法解决这个问题...
约
如何public override int GetHashCode()
{
return id.GetHashCode() ^ name.GetHashCode();
}