我有一个类,其相等性基于两个字段,如果其中一个字段相等,则该类型的对象被视为相等。我如何为这样的 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;
}
有帮助吗?

解决方案

我认为不存在重要的哈希码。另外,你的 equals() 违反总合同 API中规定 - - 这是 不及物:

(1,2) 等于 (1,3)

(4,3) 等于 (1,3)

(4,3)不等于(1,2).


为了完整起见,我向您介绍 双向飞碟-尼科 证明=)

宣称: 哈希码必须是平凡的常量函数。

证明:让 (a,b)(c,d) 是具有不同哈希码的两个对象,即 h(a,b) ≠ h(c,d). 。考虑对象 (a,d). 。根据OP的定义, (a,d) 等于 (a,b), , 和 (a,d) 等于 (c,d). 。由此可知 哈希码合约h(a,d) = h(a,b) = h(c,d);矛盾。

其他提示

确定,在方案中,忽略用于第二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();
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top