Menu
Coddy logo textTech

equals() と hashCode()

CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 42/87。

Javaでオブジェクトを比較する場合、== 演算子は、2つの参照が同じメモリ位置を指しているかどうかをチェックします。オブジェクトの実際の値を比較するには、equals() メソッドをオーバーライドする必要があります。

public class Person {
    private String name;
    private int age;
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && name.equals(person.name);
    }
}

equals() メソッドは標準的なパターンに従います。まず同じオブジェクトであるかを確認し、次に型を検証し、最後に該当するフィールドを比較します。

equals() をオーバーライドする場合は常に、hashCode() もオーバーライドしなければなりません。これはJavaにおける規約です。等価なオブジェクトは同じハッシュコードを持たなければなりません。HashMapHashSet のようなハッシュベースのコレクションは、正しく機能するためにこのルールに依存しています。

@Override
public int hashCode() {
    return Objects.hash(name, age);
}

Objects.hash() ユーティリティメソッドは、equals() で使用されるのと同じフィールドからハッシュコードを生成します。2つの Person オブジェクトが同じ名前と年齢を持っている場合、それらは等価であるとみなされ、同一のハッシュコードを生成します。これにより、コレクション内での一貫した動作が保証されます。

challenge icon

チャレンジ

簡単

オブジェクトの等価性を適切に実装した学生記録システムを構築しましょう。2人の学生が、メモリ内の同じオブジェクトであるかどうかに関わらず、同じ学生IDと名前を持っている場合に等しいと見なされる Student クラスを作成します。

コードは2つのファイルに分けて構成します:

  • Student.java: 3つのプライベートフィールド studentId (String)、name (String)、gpa (double) を持つ学生を表すクラスを作成します。すべてのフィールドを初期化するコンストラクタと、各フィールドのゲッターメソッドを含めてください。

    2つの Student オブジェクトが同じ studentId かつ同じ name を持っている場合に等しいと見なされるように、equals() メソッドをオーバーライドします。標準的なパターンに従ってください:同一リファレンスのチェック、nullと型のチェック、そして関連するフィールドの比較を行います。

    equals() で使用したのと同じフィールドを使用して、Objects.hash() を用いて hashCode() メソッドをオーバーライドします。ファイルの先頭で java.util.Objects をインポートすることを忘れないでください。

  • Main.java: 学生オブジェクトを比較することで、Student クラスを実際に動かしてみましょう。2人の学生を表す6つの入力を受け取ります:1人目の学生のID、名前、GPA、続いて2人目の学生のID、名前、GPAです。

    両方の Student オブジェクトを作成し、3つの比較を実行して結果を出力します:

    1. Same reference: に続けて、1人目の学生が自分自身と等しいかどうかを出力します(常に true になるはずです)。
    2. Content equality: に続けて、1人目の学生が2人目の学生と等しいかどうかを出力します(equals の実装に基づきます)。
    3. Hash codes match: に続けて、両方の学生が同じハッシュコードを持っているかどうかを出力します。

6つの入力を受け取ります:1人目の学生のID (String)、1人目の学生の名前 (String)、1人目の学生のGPA (double)、2人目の学生のID (String)、2人目の学生の名前 (String)、2人目の学生のGPA (double)。

2人の学生のIDと名前が一致する場合、equals() が true を返し、かつハッシュコードも一致することに注目してください。これが維持しなければならないコントラクト(規約)です!

自分で試してみよう

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 1人目の生徒のデータを読み込む
        String id1 = scanner.nextLine();
        String name1 = scanner.nextLine();
        double gpa1 = scanner.nextDouble();
        scanner.nextLine(); // 改行文字を読み飛ばす
        
        // 2人目の生徒のデータを読み込む
        String id2 = scanner.nextLine();
        String name2 = scanner.nextLine();
        double gpa2 = scanner.nextDouble();
        
        // TODO: 入力データを使用して2つの Student オブジェクトを作成する
        
        // TODO: "Same reference: " に続けて、student1 が自身と等しいかどうかを出力する
        
        // TODO: "Content equality: " に続けて、student1 と student2 が等しいかどうかを出力する
        
        // TODO: "Hash codes match: " に続けて、両方の生徒が同じハッシュコードを持っているかどうかを出力する
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン