AIによる要約
equalsはオブジェクトの同一性を判断する重要なメソッドですが、hashCodeとセットで考えないとHashSetやHashMapで不具合につながります。この記事では、初学者がつまずきやすい理由を現場目線で整理します。


前回の文字列比較では、==ではなくequalsを使う話をしました。
次に現場で出てくるのが、自分で作ったクラスのequalsとhashCodeです。
この記事のポイント
equalsは「同じ値として扱うか」を決めるhashCodeはHashSetやHashMapの探索に使われるequalsを上書きするならhashCodeも合わせて実装する- ID値を持つクラスやキー用クラスではレビューされやすい
equalsだけでは足りない理由
HashSetやHashMapは、まずhashCodeで大まかな置き場所を決め、その後にequalsで同じかどうかを確認します。
つまり、equalsでは同じなのにhashCodeが違うと、同じ値なのに別物として扱われる可能性があります。
基本の実装例
import java.util.Objects;
public class UserId {
private final String value;
public UserId(String value) {
this.value = Objects.requireNonNull(value);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof UserId other)) {
return false;
}
return Objects.equals(this.value, other.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
}
ポイントは、比較対象に使ったフィールドと、ハッシュ値に使うフィールドを揃えることです。
現場ではどんなクラスで必要になるか
- ユーザーID、商品コード、注文番号などの値オブジェクト
- Setに入れて重複排除したいクラス
- Mapのキーとして使うクラス
- テストでオブジェクト同士を比較したいクラス
ただし、すべてのクラスに必ず必要というわけではありません。DTOやEntityでは、プロジェクトの方針やフレームワークの扱いも確認します。
レビューで見られるポイント
equals/hashCodeの確認リスト
equalsとhashCodeを片方だけ実装していないか- 比較に使うフィールドが妥当か
- 変更される値をMapのキーに使っていないか
- IDE生成コードやLombok任せにせず、意味を理解しているか
なぜHashSetで急に問題になるのか
equals と hashCode の問題は、普通の画面表示では気づきにくいです。ところが、重複排除やMapのキーとして使った瞬間に不具合として表に出ます。
Set<UserId> userIds = new HashSet<>();
userIds.add(new UserId("U001"));
userIds.add(new UserId("U001"));
System.out.println(userIds.size()); // 期待は1件。でも実装次第で2件になる
業務システムでは、注文番号、商品コード、ユーザーIDなどをSetで重複排除する場面があります。equals だけ実装して hashCode がズレていると、同じIDなのに重複して扱われる可能性があります。
レビューで確認される実装の一貫性
レビューでは、単にメソッドがあるかではなく、equals と hashCode が同じフィールドを基準にしているかを見ます。
@Override
public boolean equals(Object obj) {
if (!(obj instanceof UserId other)) {
return false;
}
return Objects.equals(this.value, other.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
// レビューコメント例 // equalsではvalueを見ていますが、hashCodeでは別フィールドを使っています。 // HashSetやHashMapで同一判定が崩れるので、同じ基準に揃えてください。
equals/hashCodeを確認する場面
- Setで重複排除するクラス
- Mapのキーに使うクラス
- IDやコード値を表す値オブジェクト
- テストでオブジェクト同士を比較するクラス
まとめ
equalsとhashCodeは、コレクションと一緒に使うと重要度が一気に上がります。自分で値の同一性を決めるクラスでは、必ずセットで考えましょう。