Java で equals メソッドと hashCode メソッドをオーバーライドする必要があるのはなぜですか? 質問する

Java で equals メソッドと hashCode メソッドをオーバーライドする必要があるのはなぜですか? 質問する

最近これを読みました開発者作業ドキュメント

このドキュメントではhashCode()、 をequals()効果的かつ正確に定義することについて説明していますが、なぜこれら 2 つのメソッドをオーバーライドする必要があるのか​​がわかりません。

これらの方法を効率的に実装するにはどうすればよいでしょうか?

ベストアンサー1

ジョシュア・ブロックはEffective Javaについてこう語る

equals() をオーバーライドするすべてのクラスで hashCode() をオーバーライドする必要があります。オーバーライドしないと、Object.hashCode() の一般規約に違反することになり、HashMap、HashSet、Hashtable などのすべてのハッシュベースのコレクションと組み合わせてクラスが適切に機能しなくなります。

equals()オーバーライドせずに をオーバーライドしhashCode()、 を使用しようとした場合に何が起こるかの例を使用して理解してみましょうMap

このようなクラスがあり、 の 2 つのオブジェクトは、が等しい場合 ( Eclipse によって生成され、の場合) にMyClass等しいとします。importantFieldhashCode()equals()

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

のみがequalsオーバーライドされる場合、最初に を呼び出すと はmyMap.put(first,someValue)何らかのバケットにハッシュされ、 を呼び出すとmyMap.put(second,someOtherValue)別のバケットにハッシュされます ( が異なるためhashCode)。 したがって、それらは等しいものの、同じバケットにハッシュされないため、マップはそれを認識できず、両方ともマップ内に残ります。


equals()をオーバーライドする場合は をオーバーライドする必要はありませんが、 の 2 つのオブジェクトが等しい場合に が等しいことがわかっているのに をオーバーライドしないというhashCode()特定のケースで何が起こるかを見てみましょう。MyClassimportantFieldequals()

上書きのみhashCode

オーバーライドのみの場合はhashCode、呼び出し時にmyMap.put(first,someValue)最初に取得し、計算してhashCode指定されたバケットに格納します。その後、呼び出し時に、myMap.put(second,someOtherValue)最初の値を2番目の値に置き換えます。マップドキュメントこれらは等しいからです (ビジネス要件によると)。

しかし、問題は、equals が再定義されていないため、マップがsecondバケットをハッシュして反復処理し、が truekであるオブジェクトがあるかどうかを調べるときに、 となるsecond.equals(k)オブジェクトが見つからないことです。second.equals(first)false

分かりやすくなったと思います

おすすめ記事