Java で 2 つのオブジェクトが等しいかどうかをチェックする方法

JavaJavaBeginner
今すぐ練習

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

この実験では、Java で 2 つのオブジェクトが等しいかどうかをチェックする方法を学びます。オブジェクトの比較における == 演算子と equals() メソッドの基本的な違いを探ります。

まず、組み込みの equals() メソッドを使ってオブジェクトを比較し、さまざまなデータ型での動作を理解します。次に、独自のカスタムクラスで equals() メソッドをオーバーライドして、オブジェクトの論理的な等価性を定義する方法を学びます。最後に、等価性チェックを行う際に null オブジェクトを処理する重要な考慮事項に対処し、潜在的な NullPointerException エラーを防ぎます。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL java(("Java")) -.-> java/StringManipulationGroup(["String Manipulation"]) java(("Java")) -.-> java/ProgrammingTechniquesGroup(["Programming Techniques"]) java(("Java")) -.-> java/ObjectOrientedandAdvancedConceptsGroup(["Object-Oriented and Advanced Concepts"]) java(("Java")) -.-> java/SystemandDataProcessingGroup(["System and Data Processing"]) java/StringManipulationGroup -.-> java/strings("Strings") java/ProgrammingTechniquesGroup -.-> java/method_overriding("Method Overriding") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/classes_objects("Classes/Objects") java/SystemandDataProcessingGroup -.-> java/object_methods("Object Methods") subgraph Lab Skills java/strings -.-> lab-560013{{"Java で 2 つのオブジェクトが等しいかどうかをチェックする方法"}} java/method_overriding -.-> lab-560013{{"Java で 2 つのオブジェクトが等しいかどうかをチェックする方法"}} java/classes_objects -.-> lab-560013{{"Java で 2 つのオブジェクトが等しいかどうかをチェックする方法"}} java/object_methods -.-> lab-560013{{"Java で 2 つのオブジェクトが等しいかどうかをチェックする方法"}} end

equals() メソッドを使った等価性の判定

このステップでは、Java で equals() メソッドを使ってオブジェクトを比較する方法を探ります。== 演算子は 2 つのオブジェクト参照がメモリ内のまったく同じオブジェクトを指しているかどうかをチェックしますが、equals() メソッドは 2 つのオブジェクトが論理的に等しいか、つまり同じ値や状態を表しているかをチェックするように設計されています。

この概念を実証するために、簡単な Java ファイルを作成して始めましょう。

  1. WebIDE を開き、~/project ディレクトリにいることを確認します。ターミナルのプロンプトを見るか、pwd と入力して Enter キーを押すことで確認できます。

  2. ~/project ディレクトリに EqualityDemo.java という名前の新しいファイルを作成します。左側のファイルエクスプローラーで右クリックして「New File」を選択し、EqualityDemo.java と入力することができます。

  3. EqualityDemo.java ファイルをエディタで開き、次のコードを貼り付けます。

    public class EqualityDemo {
        public static void main(String[] args) {
            String str1 = new String("hello");
            String str2 = new String("hello");
            String str3 = str1;
    
            System.out.println("Comparing String objects:");
            System.out.println("str1 == str2: " + (str1 == str2));
            System.out.println("str1.equals(str2): " + str1.equals(str2));
            System.out.println("str1 == str3: " + (str1 == str3));
            System.out.println("str1.equals(str3): " + str1.equals(str3));
    
            System.out.println("\nComparing primitive types (int):");
            int num1 = 10;
            int num2 = 10;
            System.out.println("num1 == num2: " + (num1 == num2));
        }
    }

    このコードでは:

    • 同じ内容("hello")を持つ 2 つの String オブジェクト str1str2new String() を使って作成します。これにより、メモリ内に別々のオブジェクトが作成されます。
    • 3 つ目の String 参照 str3 を作成し、str1 と同じオブジェクトを指すようにします。
    • ==equals() の両方を使って str1str2、および str1str3 を比較します。
    • == を使ってプリミティブ型の int を比較する例も示しています。equals() はオブジェクトに対して使用され、プリミティブ型には使用されないことを覚えておいてください。
  4. EqualityDemo.java ファイルを保存します(Ctrl+S または Cmd+S)。

  5. WebIDE の下部にあるターミナルを開きます。

  6. 次のコマンドを入力して Enter キーを押し、Java プログラムをコンパイルします。

    javac EqualityDemo.java

    エラーがなければ、何も出力されないはずです。

  7. 次のコマンドを入力して Enter キーを押し、コンパイルされたプログラムを実行します。

    java EqualityDemo

    次のような出力が表示されるはずです。

    Comparing String objects:
    str1 == str2: false
    str1.equals(str2): true
    str1 == str3: true
    str1.equals(str3): true
    
    Comparing primitive types (int):
    num1 == num2: true

    str1 == str2false になるのは、メモリ内で異なるオブジェクトであるためです。ただし、str1.equals(str2)true になります。なぜなら、String クラスの equals() メソッドは文字列の実際の内容を比較するようにオーバーライドされているからです。str1 == str3true になります。なぜなら、str3str1 とまったく同じオブジェクトを指しているからです。

これは、Java でオブジェクトを比較する際の ==(参照の等価性)と equals()(論理的な等価性)の重要な違いを示しています。プリミティブ型には、== が値の比較に使用されます。

カスタムクラスで equals() をオーバーライドする

前のステップでは、String オブジェクトに対する equals() メソッドの動作を見ました。String クラスは、内容に基づく意味のある比較を行うために、デフォルトの equals() メソッド(Object クラスから継承されたもの)をオーバーライドしています。

しかし、独自のカスタムクラスを作成する場合、Object から継承されたデフォルトの equals() メソッドは単に == 演算子を使用します。つまり、参照の等価性のみをチェックします。カスタムクラスのオブジェクトをその属性に基づいて(論理的な等価性で)比較するには、自分で equals() メソッドをオーバーライドする必要があります。

このステップでは、簡単な Person クラスを作成し、その equals() メソッドをオーバーライドします。

  1. WebIDE で ~/project ディレクトリにいることを確認します。

  2. ~/project ディレクトリに Person.java という名前の新しいファイルを作成します。

  3. Person.java を開き、Person クラスの次のコードを貼り付けます。

    public class Person {
        private String name;
        private int age;
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    
        // Default equals() method (inherited from Object) would only check reference equality
        // We need to override it to check for logical equality based on name and age
        @Override
        public boolean equals(Object obj) {
            // Step 1: Check if the objects are the same instance
            if (this == obj) {
                return true;
            }
    
            // Step 2: Check if the object is null or of a different class
            if (obj == null || getClass() != obj.getClass()) {
                return false;
            }
    
            // Step 3: Cast the object to the correct type
            Person person = (Person) obj;
    
            // Step 4: Compare the relevant attributes
            return age == person.age &&
                   name.equals(person.name); // Use equals() for String comparison
        }
    }

    この Person クラスでは:

    • 2 つのプライベート属性 nameString 型)と ageint 型)があります。
    • これらの属性を初期化するコンストラクタがあります。
    • 属性にアクセスするためのゲッターメソッドがあります。
    • equals() メソッドをオーバーライドしています。オーバーライドされた equals() メソッド内のステップを見てみましょう。
      • if (this == obj):これは最適化です。2 つの参照がまったく同じオブジェクトを指している場合、それらは確かに等しいです。
      • if (obj == null || getClass() != obj.getClass()):これは、比較対象のオブジェクトが null であるか、Person クラスのインスタンスでないかをチェックします。どちらかが真であれば、それらは等しくないはずです。
      • Person person = (Person) obj;:汎用の ObjectPerson オブジェクトにキャストして、その nameage 属性にアクセスできるようにします。
      • return age == person.age && name.equals(person.name);:これが論理的な比較の核心です。age が同じであること(プリミティブ型の int には == を使用)、および name が同じであること(String オブジェクトには equals() を使用)をチェックします。
  4. Person.java ファイルを保存します。

  5. 次に、オーバーライドした equals() メソッドをテストするために、PersonEqualityDemo.java という別のファイルを作成しましょう。このファイルを ~/project ディレクトリに作成します。

  6. PersonEqualityDemo.java を開き、次のコードを貼り付けます。

    public class PersonEqualityDemo {
        public static void main(String[] args) {
            Person person1 = new Person("Alice", 30);
            Person person2 = new Person("Alice", 30);
            Person person3 = new Person("Bob", 25);
            Person person4 = person1;
    
            System.out.println("Comparing Person objects:");
            System.out.println("person1 == person2: " + (person1 == person2));
            System.out.println("person1.equals(person2): " + person1.equals(person2));
            System.out.println("person1 == person3: " + (person1 == person3));
            System.out.println("person1.equals(person3): " + person1.equals(person3));
            System.out.println("person1 == person4: " + (person1 == person4));
            System.out.println("person1.equals(person4): " + person1.equals(person4));
        }
    }

    このデモクラスでは、いくつかの Person オブジェクトを作成し、== とオーバーライドした equals() メソッドの両方を使用して比較します。

  7. PersonEqualityDemo.java ファイルを保存します。

  8. ターミナルを開きます。~/project ディレクトリにいることを確認します。

  9. 両方の Java ファイルをコンパイルします。一度に複数のファイルをコンパイルすることができます。

    javac Person.java PersonEqualityDemo.java

    これにより、Person.classPersonEqualityDemo.class ファイルが作成されるはずです。

  10. デモプログラムを実行します。

    java PersonEqualityDemo

    次のような出力が表示されるはずです。

    Comparing Person objects:
    person1 == person2: false
    person1.equals(person2): true
    person1 == person3: false
    person1.equals(person3): false
    person1 == person4: true
    person1.equals(person4): true

    予想通り、person1 == person2false です。なぜなら、それらは別々のオブジェクトだからです。しかし、person1.equals(person2)true です。なぜなら、オーバーライドしたメソッドによると、それらの nameage が同じだからです。person1person3 はどちらの比較方法でも等しくありません。person1person4 は、同じオブジェクトを参照しているため、どちらの比較方法でも等しいです。

equals() メソッドをオーバーライドすることで、カスタムクラスのオブジェクトに対して、単なるメモリ位置ではなく、論理的な状態に基づいて「等しい」という意味を定義することができます。

等価性判定における null オブジェクトの扱い

前のステップでは、Person クラスの equals() メソッドをオーバーライドして、オブジェクトを属性に基づいて比較することに成功しました。堅牢な equals() メソッドを記述する上で重要な点の 1 つは、潜在的な null 値を適切に扱うことです。null オブジェクトに対してメソッドを呼び出そうとすると、NullPointerException が発生します。これは Java でよく見られるエラーです。

Person.java でオーバーライドした equals() メソッドには、既に null チェックが含まれています。if (obj == null || getClass() != obj.getClass()) という部分です。これは、比較対象のオブジェクトが null である場合を扱う標準的な方法です。

このステップでは、オブジェクトを null と比較したときに何が起こるかを示し、equals() メソッドが正しく処理することを確認します。

  1. WebIDE で ~/project ディレクトリにいることを確認します。

  2. 前のステップで作成した PersonEqualityDemo.java ファイルを開きます。

  3. 既存の比較文の後に、main メソッドに次の行を追加します。

    System.out.println("\nComparing with null:");
    System.out.println("person1.equals(null): " + person1.equals(null));

    このコードは、単に person1null の比較を追加するだけです。

  4. PersonEqualityDemo.java ファイルを保存します。

  5. ターミナルを開きます。~/project ディレクトリにいることを確認します。

  6. 変更した PersonEqualityDemo.java ファイルをコンパイルします。

    javac PersonEqualityDemo.java

    変更したファイルだけを再コンパイルすればよいことを覚えておいてください。このステップでは Person.java は変更されていないので、PersonEqualityDemo.java だけをコンパイルすればいいです。

  7. コンパイルしたプログラムを実行します。

    java PersonEqualityDemo

    これまでの出力の後に、null との新しい比較結果が表示されるはずです。

    Comparing Person objects:
    person1 == person2: false
    person1.equals(person2): true
    person1 == person3: false
    person1.equals(person3): false
    person1 == person4: true
    person1.equals(person4): true
    
    Comparing with null:
    person1.equals(null): false

    person1.equals(null): false という出力は、オーバーライドした equals() メソッドが null との比較を正しく処理し、NullPointerException を投げることなく false を返すことを確認しています。これは、Person クラスの equals() メソッドの if (obj == null || getClass() != obj.getClass()) という行が、obj の属性にアクセスしようとする前に null をチェックするからです。

null を適切に扱うことは、Java で堅牢なコードを書く上で重要な部分です。特にオブジェクトの比較を行うときには、オーバーライドした equals() メソッドの最初に null チェックを必ず含めてください。

まとめ

この実験では、Java で 2 つのオブジェクトが等しいかどうかをチェックする方法を学びました。まず、参照の等価性をチェックする == 演算子と、論理的な等価性をチェックする equals() メソッドの違いを理解しました。これを String オブジェクトとプリミティブ型を使って実証し、オブジェクトに対して ==equals() が異なる動作をすることを確認しました。

次に、カスタムクラスで equals() メソッドをオーバーライドして、オブジェクトの等価性を判断する独自の基準を定義する方法を探りました。これは、カスタムオブジェクトがメモリ位置ではなく、内容や状態に基づいて比較されるようにするために重要です。最後に、equals() メソッド内で null オブジェクトを適切に扱うことの重要性を学びました。これにより、NullPointerException を防ぎ、堅牢な等価性チェックを行うことができます。