1. ホーム
  2. java

[解決済み] JavaでequalsとhashCodeのメソッドをオーバーライドする必要があるのはなぜですか?

2022-03-21 12:02:08

質問

最近、こんな記事を読みました。 デベロッパーワークスドキュメント .

を定義するためのドキュメントです。 hashCode()equals() を効果的かつ正確に実行することができます。しかし、なぜこの2つのメソッドをオーバーライドする必要があるのかが理解できません。

これらのメソッドを効率的に実装するには、どのような判断をすればよいでしょうか。

どのように解決するのか?

Effective JavaについてJoshua Blochが語る

<ブロッククオート

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

をオーバーライドするとどうなるのか、例を挙げて理解してみましょう。 equals() をオーバーライドせずに hashCode() を使用しようとすると Map .

このようなクラスがあり、2つのオブジェクトが MyClass が等しい場合、その importantField が等しい(と hashCode()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

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


をオーバーライドする必要はありませんが equals() をオーバーライドすると hashCode() の2つのオブジェクトがあることを知っている場合、何が起こるか見てみましょう。 MyClass が等しい場合、その importantField は等しいが、オーバーライドはしない。 equals() .

オーバーライドのみ hashCode

をオーバーライドするだけなら hashCode を呼び出すと myMap.put(first,someValue) は、まず最初に、その hashCode を作成し、所定のバケットに格納する。そして myMap.put(second,someOtherValue) と同じように、1番目を2番目に置き換える必要があります。 マップドキュメント というのは、(ビジネス要件によれば)両者は等しいからです。

しかし問題は、equalsが再定義されていないため、マップがハッシュ化したときに second というオブジェクトがあるかどうか、バケツを反復して調べます。 k そのような second.equals(k) が真であれば second.equals(first)false .

分かりやすかったでしょうか?