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

问题描述:

最近我通读了这个
开发者工作文件一>。

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

The document is all about defining hashCode() and equals() effectively and correctly, however I am not able to figure out why we need to override these two methods.

如何有效地决定实施这些方法?

How can I take the decision to implement these methods efficiently?

Joshua Bloch says on Effective Java


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

You must override hashCode() in every class that overrides equals(). Failure to do so will result in a violation of the general contract for Object.hashCode(), which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.

让我们尝试理解它,如果我们覆盖 equals()将会发生什么重写 hashCode()并尝试使用 Map

Let's try to understand it with an example of what would happen if we override equals() without overriding hashCode() and attempt to use a Map.

假设我们有一个这样的类,如果 MyClass 的两个对象的 importantField 相等(带有 hashCode()等于()由eclipse生成)

Say we have a class like this and that two objects of MyClass are equal if their importantField is equal (with hashCode() and equals() generated by 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;
    }

    public String getEqualField() {
        return importantField;
    }

    public String getAnotherField() {
        return 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;
    }

}






仅覆盖等于


Override only equals

如果仅等于被覆盖,然后当你调用 myMap.put(first,someValue)首先将哈希到某个桶并且当你调用 myMap.put(second,someOtherValue)它将散列到其他一些桶(因为它们有不同的 hashCode )。所以,虽然它们是相同的,因为它们没有哈希到同一个桶,地图无法实现它,并且它们都留在地图中。

If only equals is overriden, then when you call myMap.put(first,someValue) first will hash to some bucket and when you call myMap.put(second,someOtherValue) it will hash to some other bucket (as they have a different hashCode). So, although they are equal, as they don't hash to the same bucket, the map can't realize it and both of them stay in the map.

如果我们覆盖 hashCode()$ c $,则无需覆盖 equals() c>,让我们看看在这个特殊情况下会发生什么,我们知道 MyClass 的两个对象是相等的,如果他们的 importantField 相等但我们不会覆盖 equals()

Although it is not necessary to override equals() if we override hashCode(), let's see what would happen in this particular case where we know that two objects of MyClass are equal if their importantField is equal but we do not override equals().

仅覆盖 hashCode

Override only hashCode

想象一下你有这个

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

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

If you only override hashCode then when you call myMap.put(first,someValue) it takes first, calculates its hashCode and stores it in a given bucket. Then when you call myMap.put(second,someOtherValue) it should replace first with second as per the Map Documentation because they are equal (according to the business requirement).

但问题是equals没有重新定义,所以当地图哈希 second 并遍历存储桶,查看是否存在对象 k ,使得 second.equals(k)为真它找不到任何 second.equals(第一个) false

But the problem is that equals was not redefined, so when the map hashes second and iterates through the bucket looking if there is an object k such that second.equals(k) is true it won't find any as second.equals(first) will be false.

希望很清楚