1. 概要

このチュートリアルでは、ArraysクラスdeepEqualsメソッドの詳細について詳しく説明します。 この方法をいつ使用すべきかを確認し、いくつかの簡単な例を見ていきます。

java.util.Arrays クラスのさまざまなメソッドの詳細については、クイックガイドをご覧ください。

2. 目的

2つのネストされた配列または多次元配列間の同等性を確認する場合は、deepEqualsメソッドを使用する必要があります。 また、後で説明するように、ユーザー定義オブジェクトで構成される2つの配列を比較する場合は、equalsメソッドをオーバーライドする必要があります。

それでは、deepEqualsメソッドの詳細を調べてみましょう。

2.1. 構文

まず、メソッドシグネチャを見てみましょう。

public static boolean deepEquals(Object[] a1, Object[] a2)

メソッドのシグネチャから、deepEqualsを使用してプリミティブデータ型の2つの一次元配列を比較できないことがわかります。 このためには、プリミティブ配列を対応するラッパーにボックス化するか、プリミティブ配列のメソッドがオーバーロードされているArrays.equalsメソッドを使用する必要があります。

2.2. 実装

メソッドの内部実装を分析することにより、メソッドは配列の最上位要素をチェックするだけでなく、そのすべてのサブ要素も再帰的にチェックすることがわかります。

したがって、自己参照を持つ配列でdeepEqualsメソッドを使用することは避けてください。これにより、java.lang.StackOverflowErrorが発生します。

次に、このメソッドからどのような出力を取得できるかを調べてみましょう。

3. 出力

Arrays.deepEqualsメソッドは次を返します。

  • true 両方のパラメーターが同じオブジェクトの場合(同じ参照を持つ)
  • true両方のパラメーターがnullの場合
  • false2つのパラメーターの1つだけがnullの場合
  • false配列の長さが異なる場合
  • true両方のアレイが空の場合
  • true 配列に同じ数の要素が含まれ、サブ要素のすべてのペアが完全に等しい場合
  • falseその他の場合

次のセクションでは、いくつかのコード例を見ていきます。

4. 例

次に、deepEqualsメソッドの動作を確認します。 さらに、deepEqualsメソッドを同じArraysクラスのequalsメソッドと比較します。

4.1. 一次元配列

まず、簡単な例から始めて、Object型の2つの一次元配列を比較してみましょう。

    Object[] anArray = new Object[] { "string1", "string2", "string3" };
    Object[] anotherArray = new Object[] { "string1", "string2", "string3" };

    assertTrue(Arrays.equals(anArray, anotherArray));
    assertTrue(Arrays.deepEquals(anArray, anotherArray));

equalsメソッドとdeepEqualsメソッドの両方がtrueを返すことがわかります。 配列の1つの要素がnullである場合に何が起こるかを調べてみましょう。

    Object[] anArray = new Object[] { "string1", null, "string3" };
    Object[] anotherArray = new Object[] { "string1", null, "string3" };

    assertTrue(Arrays.equals(anArray, anotherArray));
    assertTrue(Arrays.deepEquals(anArray, anotherArray));

両方のアサーションが通過していることがわかります。 したがって、 deepEquals メソッドを使用する場合、null値は入力配列の任意の深さで受け入れられると結論付けることができます。

しかし、もう1つ試して、ネストされた配列の動作を確認してみましょう。

    Object[] anArray = new Object[] { "string1", null, new String[] {"nestedString1", "nestedString2" }};
    Object[] anotherArray = new Object[] { "string1", null, new String[] {"nestedString1", "nestedString2" } };

    assertFalse(Arrays.equals(anArray, anotherArray));
    assertTrue(Arrays.deepEquals(anArray, anotherArray));

ここで、deepEqualstrueを返し、equalsfalseを返すことがわかります。 これは、 deepEqualsが配列に遭遇すると再帰的に自分自身を呼び出すのに対し、equalsはサブ配列の参照を比較するだけだからです。

4.2. プリミティブ型の多次元配列

次に、多次元配列を使用して動作を確認しましょう。 次の例では、2つのメソッドの出力が異なり、多次元配列を比較するときにequalsメソッドの代わりにdeepEqualsを使用する必要があることを強調しています。

    int[][] anArray = { { 1, 2, 3 }, { 4, 5, 6, 9 }, { 7 } };
    int[][] anotherArray = { { 1, 2, 3 }, { 4, 5, 6, 9 }, { 7 } };

    assertFalse(Arrays.equals(anArray, anotherArray));
    assertTrue(Arrays.deepEquals(anArray, anotherArray));

4.3. ユーザー定義オブジェクトの多次元配列

最後に、ユーザー定義オブジェクトの2つの多次元配列の同等性をテストするときの、deepEqualsおよびequalsメソッドの動作を確認しましょう。

簡単なPersonクラスを作成することから始めましょう。

    class Person {
        private int id;
        private String name;
        private int age;

        // constructor & getters & setters

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (!(obj instanceof Person))
                return false;
            Person person = (Person) obj;
            return id == person.id && name.equals(person.name) && age == person.age;
        }
    }

Personクラスのequalsメソッドをオーバーライドする必要があります。 それ以外の場合、デフォルトの equals メソッドは、オブジェクトの参照のみを比較します。

また、この例には関係ありませんが、 equals メソッドをオーバーライドするときは、に違反しないように、常にhashCodeをオーバーライドする必要があることを考慮に入れましょう。 ]契約

次に、Personクラスの2つの多次元配列を比較できます。

    Person personArray1[][] = { { new Person(1, "John", 22), new Person(2, "Mike", 23) },
      { new Person(3, "Steve", 27), new Person(4, "Gary", 28) } };
    Person personArray2[][] = { { new Person(1, "John", 22), new Person(2, "Mike", 23) }, 
      { new Person(3, "Steve", 27), new Person(4, "Gary", 28) } };
        
    assertFalse(Arrays.equals(personArray1, personArray2));
    assertTrue(Arrays.deepEquals(personArray1, personArray2));

サブ要素を再帰的に比較した結果、2つの方法でも結果が異なります。

最後に、 Objects.deepEqualsメソッドは、2つの Object 配列で呼び出されたときに、Arrays.deepEqualsメソッドを内部的に実行することに注意してください。

    assertTrue(Objects.deepEquals(personArray1, personArray2));

5. 結論

このクイックチュートリアルでは、オブジェクトまたはプリミティブ型の2つのネストされた配列または多次元配列間の等式を比較する場合に、Arrays.deepEqualsメソッドを使用する必要があることを学びました。

いつものように、記事の完全なソースコードは、GitHubから入手できます。