Java 使用hashCode实现equals是一个禁忌吗?

Java 使用hashCode实现equals是一个禁忌吗?,java,equals,hashcode,Java,Equals,Hashcode,我一直在尝试以下equals&hashCode的实现: @Override public boolean equals(Object obj) { return obj != null && hashCode() == obj.hashCode(); } @Override public int hashCode() { return new HashCodeBuilder().append(myField1).append(myField2).toHashCo

我一直在尝试以下equals&hashCode的实现:

@Override
public boolean equals(Object obj) {
    return obj != null && hashCode() == obj.hashCode();
}

@Override
public int hashCode() {
    return new HashCodeBuilder().append(myField1).append(myField2).toHashCode();
}
基本上,我希望
equals
对于任何两个具有相同
hashCode
的类返回
true
,这归结为我用来生成hashCode的字段的值

我知道,对于这些字段中恰好具有相等值的不同类,这也会返回
true


问题:这种实现的陷阱是什么?哈希冲突。具有不同字段值的实例可能具有匹配的哈希代码,因此比较相等。我不知道为什么这会有用。

正如Oli所说,您可以确保两个具有相同数据的对象匹配,但也可以确保一个具有相同哈希代码的不匹配对象匹配。请记住,您使用哈希代码对哈希表中的元素进行排序,以优化排序,而不是进行比较,为了确保使用equals方法,您应该比较对象的精细数据,如:

public boolean equals(Object obj) {
    if (obj instanceof THISOBJECT) {
        THISOBJECT other = (THISOBJECT) obj;
        return getID.equals(other.getID);
    }
    return false;
}

如果测试两个对象的相等性代价高昂,并且如果对象的哈希代码已知,那么测试哈希代码作为测试相等性的第一步可能会有所帮助。如果散列码不相等,则无需进一步查找。如果它们相等,那么就更详细地检查问题。例如,假设其中一个有100000个字符串,而这些字符串恰好只在最后十个字符中有所不同(但没有理由认为会出现这种情况)。即使哈希代码的错误匹配率为1%,在详细检查字符串内容之前检查哈希代码也可以提供近100倍的加速,而不是重复检查每个字符串的前9990个字符


哈希代码的目标通常不是唯一的,而是降低涉及虚假哈希匹配的比较成本,使其与哈希代码计算的成本处于同一水平。如果给定的哈希代码生成了如此多的错误匹配,以至于处理这些错误匹配所花费的时间占了计算哈希代码的时间,那么如果能够减少错误匹配的数量,那么花更多的时间计算哈希代码可能是值得的。如果散列算法非常有效,计算散列码所花费的时间占了错误匹配所花费的时间的主要部分,那么即使错误匹配的数量会增加,也最好使用更快的散列算法。

@Jonas Eicher,您可能想看看.Hmm,比较散列码(通常)需要处理所有N个字符;我不确定你的例子的统计数据是否正确…@OliCharlesworth:如果要求代码比较两个以前从未见过的实例,并且不希望再次看到,那么计算hashcode就不值得了。另一方面,如果它给定了一个实例,并且必须将它(以及许多其他实例)与它将来接收的实例进行比较(想想
HashSet
),那么它可以缓存其哈希代码计算。此外,对于一些类型,如
String
,“计算”散列码1000次通常只需要在字符串上迭代一次,然后缓存计算结果[太糟糕了,Sun没有在他们的……
String
散列方法中添加一行,效果是
if(计算==0)return 0x12345678;else return computation;
,因为这个简单的更改会使字符串哈希缓存“始终”工作。是否不是每次哈希比较都调用哈希代码,每次都这样计算?或者你的意思是缓存对象的hashCode,然后在属性更改时刷新它?@JonasEicher:大多数覆盖
hashCode()
的对象在观测上是不可变的,因此属性更改不是一个因素。否则,我建议,如果哈希代码计算有任何重大成本,则属性更改应该使缓存的哈希代码无效,而不是重新计算它们。