小编典典

为什么我需要覆盖 Java 中的 equals 和 hashCode 方法?

all

最近我通读了这个 Developer Works
Document

该文档是关于定义hashCode()equals()有效和正确的,但是我无法弄清楚为什么我们需要覆盖这两种方法。

我怎样才能决定有效地实施这些方法?


阅读 129

收藏
2022-03-14

共1个答案

小编典典

Joshua Bloch 谈有效的 Java

您必须在覆盖 equals() 的每个类中覆盖 hashCode()。不这样做将导致违反 Object.hashCode()
的一般约定,这将阻止您的类与所有基于哈希的集合(包括 HashMap、HashSet 和 Hashtable)一起正常运行。

让我们尝试通过一个示例来理解它,如果我们覆盖equals()而不覆盖hashCode()并尝试使用Map.

假设我们有一个像这样的类,并且MyClass如果它们相等,则两个对象importantField相等(使用eclipsehashCode()并由equals()eclipse
生成)

public class MyClass {
    private final String importantField;
    private final String anotherField;

    public MyClass(final String equalField, final String anotherField) {
        this.importantField = equalField;
        this.anotherField = anotherField;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((importantField == null) ? 0 : importantField.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final MyClass other = (MyClass) obj;
        if (importantField == null) {
            if (other.importantField != null)
                return false;
        } else if (!importantField.equals(other.importantField))
            return false;
        return true;
    }
}

想象一下你有这个

MyClass first = new MyClass("a","first");
MyClass second = new MyClass("a","second");

仅覆盖equals

如果
onlyequals被覆盖,那么当您myMap.put(first,someValue)第一次调用时将散列到某个存储桶,当您调用myMap.put(second,someOtherValue)它时将散列到其他存储桶(因为它们具有不同的hashCode)。所以,虽然它们是相等的,因为它们没有散列到同一个桶,所以地图无法实现,它们都留在地图中。


equals()尽管如果我们 override没有必要override hashCode(),让我们看看在这种特殊情况下会发生什么,我们知道
的两个对象MyClass如果它们importantField相等但我们不 override 是相等的equals()

仅覆盖hashCode

如果您只覆盖hashCode,那么当您调用myMap.put(first,someValue)它时,首先计算它hashCode并将其存储在给定的存储桶中。然后,当您调用它时,应该根据地图文档myMap.put(second,someOtherValue)将第一个替换为第二个,因为它们是相等的(根据业务要求)。

但问题是 equals
没有被重新定义,所以当映射散列second并遍历存储桶时,如果有一个对象ksecond.equals(k)真的,它不会像second.equals(first)will
be那样找到任何对象false

希望很清楚

2022-03-14