equals()メソッドは、2つのオブジェクトが「等しい」と見なされるかどうかを定義します。デフォルトでは参照を比較します(つまり、==)。しかし、多くのクラス(例:エンティティ、値オブジェクト)は、データに基づく論理的比較を要求します。
オーバーライドするべき場合:
要件:
例:
public class Person { private String email; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return Objects.equals(email, person.email); } @Override public int hashCode() { return Objects.hash(email); } }
もし2つのオブジェクトがequals()で等しい場合、彼らのhashCode()は常に同じでなければなりませんか?
回答: はい!これはJavaの契約の要件です。しかし、その逆は正しくありません:同じhashCodeを持つ2つのオブジェクトはequals()で等しくない可能性があります — ハッシュコードは異なるオブジェクト間で衝突することがあります。
エラーの例:
person1.equals(person2); // true person1.hashCode() != person2.hashCode(); // エラー!
ストーリー
企業アプリケーションで、ユーザーエンティティがHashSetに保存されました。equalsはオーバーライドされ、hashCodeはされていませんでした。equalsに影響を与えるフィールドを変更した後、HashSetはこのオブジェクトを「失いました」:containsメソッドによる検索は、同じデータでもfalseを返しました。
ストーリー
IoTプロジェクトでは、エンティティは一時的にidだけで比較され、その後、名前を考慮したequalsにロジックが変更されました。HashMapは予測できない動作をし、キーを更新する際に重複が発生しました — 実装のバージョンの混合によりequals/hashCodeの契約が破れました。
ストーリー
注文を比較するAPIを書く際、2つの異なるクラスが独自のequalsを実装しており、1つはgetClass()を呼び出し、もう1つはinstanceofを呼び出しました。これにより、注文の非対称比較と、コレクションおよびビジネスロジックの使用時にバグが発生しました。