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() method は標準的なパターンに従います。まず同じオブジェクトかどうかを確認し、次に型を検証し、最後に関連する fields を比較します。
equals()をオーバーライドする場合は、必ずhashCode()もオーバーライドする必要があります。これはJavaにおける契約です。等しいオブジェクトは同じ hash code を持たなければなりません。HashMapやHashSetのようなハッシュベースのコレクションは、正しく機能するためにこのルールに依存しています。
@Override
public int hashCode() {
return Objects.hash(name, age);
}Objects.hash()ユーティリティメソッドは、equals()で使用されるのと同じフィールドからハッシュコードを生成します。2つのPersonオブジェクトが同じ名前と年齢を持つ場合、それらは等しいと見なされ、同一のハッシュコードを生成するため、コレクション内で一貫した動作が保証されます。
チャレンジ
簡単オブジェクトの等価性を正しく実装する学生記録システムを構築しましょう。Studentクラスを作成し、メモリ上で同じオブジェクトであるかどうかに関係なく、同じ学生 ID と名前を持つ2人の学生が等しいとみなされるようにします。
コードを2つのファイルに分けて整理します。
Student.java:学生を表すクラスを作成し、3つの private フィールド、studentId(String)、name(String)、gpa(double)を定義します。すべてのフィールドを初期化するコンストラクターと、各フィールドの getter メソッドを含めます。equals()メソッドをオーバーライドし、同じstudentIdAND 同じnameを持つ2つの Student オブジェクトが等しいとみなされるようにします。標準的なパターンに従い、同じ参照かどうか、null と型の確認を行ってから、関連するフィールドを比較します。hashCode()メソッドをオーバーライドし、equals()で使用したものと同じフィールドを使ってObjects.hash()を呼び出します。ファイルの先頭でjava.util.Objectsをインポートすることを忘れないでください。Main.java:学生オブジェクトを比較して、Student クラスを実際に動作させます。2人の学生を表す6つの入力、つまり1人目の学生の ID、名前、GPA、続いて2人目の学生の ID、名前、GPA を受け取ります。両方の Student オブジェクトを作成し、3つの比較を実行して結果を出力します。
Same reference:を出力し、その後に1人目の学生が自分自身と等しいかどうかを出力します(常に true になるはずです)Content equality:を出力し、その後に1人目の学生が2人目の学生と等しいかどうかを出力します(equals の実装に基づきます)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);
// 最初の学生のデータを読み取る
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: Print "Same reference: " followed by whether student1 equals itself
// TODO: Print "Content equality: " followed by whether student1 equals student2
// TODO: Print "Hash codes match: " followed by whether both students have the same hash code
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4継承
継承の基本 (extends)super キーワードメソッドのオーバーライド (@Override)コンストラクタチェーンObject クラス単一継承と多段階継承なぜ多重継承ができないのかまとめ:従業員の階層構造7特殊メソッドとObjectクラス
toString() メソッドequals() と hashCode()clone() メソッドcompareTo() と ComparableComparator インターフェースまとめ - カスタムソート自分で練習してみよう: Javaオンラインコンパイラ