Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 当equals()基于多个独立字段时,hashCode()方法_Java_Equals_Hashcode - Fatal编程技术网

Java 当equals()基于多个独立字段时,hashCode()方法

Java 当equals()基于多个独立字段时,hashCode()方法,java,equals,hashcode,Java,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;

我有一个类,它的相等性基于两个字段,如果其中一个字段相等,那么这种类型的对象就被认为相等。如何为这样的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;
}

最简单的方法是对每个字段的哈希码进行异或运算。在某些情况下(例如,在X,Y坐标中,当翻转X和Y时,可能会导致哈希相等的情况),但总体上相当有效。根据需要调整以减少碰撞(如有必要),以提高效率。

如何

public override int GetHashCode()
{
    return id.GetHashCode() ^ name.GetHashCode();
}

我认为不存在非平凡的哈希代码。此外,您的
equals()
违反了一般合同,因为它是不可传递的

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

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

但是
(4,3)
不等于
(1,2)


为了完整起见,我向您提供-proof=)

声明:哈希代码必须是平凡常量函数。

证明:让
(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)
;矛盾。

这个怎么样

public override int GetHashCode()
{
    return (id.ToString() + name.ToString()).GetHashCode();
}
函数应该始终返回一个“有效”哈希


编辑:刚刚注意到您使用了“或“不”和:p我怀疑这个问题是否有任何好的解决方案…

我非常肯定Zach是对的-没有非平凡的哈希代码来做这件事

伪证明:

考虑任意两个不相等的值,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()
方法是不可传递的

传递性是指三个非空的x,y,z,如果
x.equals(y)
y.equals(z)
,则
x.equals(z)
。在您的示例中,对象
x={id:1,名称:“ha”}
y={id:1,名称:“foo”}
z={id:2,名称:“bar”}
具有此属性
(x.equals(y)和y.equals(z))
。但是,
x.equals(z)
false
。每个
equals()
方法都应该有这个属性,请参阅Java API文档


回到散列函数:每个函数产生一个由
f(x)==f(y)
定义的等价性。这意味着,如果您对函数值进行比较,并希望它返回true,如果<代码> x==y(也可能在其他情况下),则您将接收传递关系,这意味着至少必须考虑对象等价性的传递闭包。在您的例子中,传递闭包是平凡的关系(一切等于一切)。这意味着您不能通过任何函数来区分不同的对象。

好的,在您的场景中,忽略API要求一秒钟,没有非常量散列函数

假设有一个hashfunction,它的

(a,b),(a,c),b=c、 然后散列(a,b)!=hash(a,c),eventhough(a,b)=(a,c)

类似地,(b,a)和(c,a)必须发出相同的哈希代码

让我们调用散列函数h。我们发现:

对于所有x,y,v,w,h(x,y)=h(x,w)=h(v,w)


因此,唯一的hashFunction可以实现您想要的功能是常量。

编辑:我没有仔细阅读这个问题

--

我将使用commons lang jar

XOR成员哈希代码应该可以工作。因为它们应该正确地实现hashCode()和equals()

但是,如果不保护哈希代码,代码可能会出错。 一旦它被散列,就不应该更改它。应该防止这种情况发生

public hashCode(){
   return new AssertionError();
}


在重读问题之后

当其中一个字段被更新时,您可以自动完成另一个字段

--

编辑:我的代码可能比我的英语更好

void setName(String value){
  this.id=Lookup.IDbyName(value);
}
void setID(String value){
  this.name=Lookup.NamebyId(value);
}
编辑2:

问题上的代码可能会出错,因为除非您同时设置了id和名称,否则将始终返回true


如果您确实想要一个执行部分相等的方法,请创建自己的名为“partialEquals()”的API。

您是否有意将相等定义为ID相等或名称相等。。“或”应该是“和”吗

如果您的意思是“AND”,那么您的hashcode应该使用与equals()相同或更少的字段(但绝不使用equals未使用的字段)进行计算


如果您的意思是“或”,则hashgcode不应在其hashcode计算中包含id或名称,这没有真正意义。

这并不能正确回答问题-当只有一个字段相同时,hashcode需要相同。您的答案要求两个字段提供相同的相等哈希值。这不适合这个问题,我也误读了这个问题。如果两个字段中的任何一个发生变化,hashcode就会发生变化。在你们的解决方案中,难道你们没有将他的equal从(other.id==this.id | | other.name==this.name)改为(other.id==this.id&&other.name==this.name)?否-这将为一个字段中不同的值生成不同的hash,而不是
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);
}