ProgrammingJava開発者

Javaにおけるequals()メソッドの特性を説明してください:いつ、なぜオーバーライドする必要があるのか、正しく実装する方法、そして不適切に使用した場合に発生する可能性のある問題は何か。

Hintsage AIアシスタントで面接を突破

回答

equals()メソッドは、2つのオブジェクトが「等しい」と見なされるかどうかを定義します。デフォルトでは参照を比較します(つまり、==)。しかし、多くのクラス(例:エンティティ、値オブジェクト)は、データに基づく論理的比較を要求します。

オーバーライドするべき場合:

  • あなたのクラスにとってオブジェクトの論理的同一性が重要な場合(例:同じメールアドレスを持つ2人のユーザーは「同じユーザー」)
  • オブジェクトがコレクション(例えば、HashSet)に保存される場合、これらはequals(およびhashCode)を使用します。

要件:

  • equalsは、反射的、対称的、推移的、一貫したものでなければならず、nullでない任意のxに対してx.equals(null)はfalseでなければなりません。
  • equalsをオーバーライドする際は、必ずhashCodeもオーバーライドしなければなりません!

例:

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を呼び出しました。これにより、注文の非対称比較と、コレクションおよびビジネスロジックの使用時にバグが発生しました。