«1. Обзор

В этом руководстве мы подробно рассмотрим метод deepEquals из класса Arrays. Мы увидим, когда нам следует использовать этот метод, и рассмотрим несколько простых примеров.

Чтобы узнать больше о различных методах класса java.util.Arrays, ознакомьтесь с нашим кратким руководством.

2. Цель

Мы должны использовать метод deepEquals, когда хотим проверить равенство между двумя вложенными или многомерными массивами. Кроме того, когда мы хотим сравнить два массива, состоящих из пользовательских объектов, как мы увидим позже, мы должны переопределить метод equals.

Теперь давайте узнаем больше о методе deepEquals.

2.1. Синтаксис

Начнем с сигнатуры метода:

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

Из сигнатуры метода видно, что мы не можем использовать deepEquals для сравнения двух одномерных массивов примитивных типов данных. Для этого мы должны либо упаковать примитивный массив в соответствующую оболочку, либо использовать метод Arrays.equals, который имеет перегруженные методы для примитивных массивов.

2.2. Реализация

Анализируя внутреннюю реализацию метода, мы видим, что метод не только проверяет элементы верхнего уровня массивов, но и рекурсивно проверяет каждый его подэлемент.

Поэтому нам следует избегать использования метода deepEquals с массивами, имеющими ссылку на себя, поскольку это приведет к ошибке java.lang.StackOverflowError.

Далее давайте выясним, какой результат мы можем получить с помощью этого метода.

3. Вывод

Метод Arrays.deepEquals возвращает:

    true, если оба параметра являются одним и тем же объектом (имеют одну и ту же ссылку) true, если оба параметра имеют значение null false, если только один из двух параметров имеет значение null false если массивы имеют разную длину true если оба массива пусты true если массивы содержат одинаковое количество элементов и каждая пара подэлементов глубоко равна false в других случаях

В следующем разделе мы рассмотрим некоторые примеры кода.

4. Примеры

Теперь пришло время посмотреть на метод deepEquals в действии. Более того, мы сравним метод deepEquals с методом equals из того же класса Arrays.

4.1. Одномерные массивы

Во-первых, давайте начнем с простого примера и сравним два одномерных массива типа Object:

    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. Давайте выясним, что происходит, если один элемент наших массивов равен нулю:

    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 нулевые значения принимаются на любой глубине входных массивов.

Но давайте попробуем еще кое-что и проверим поведение с вложенными массивами:

    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));

Здесь мы обнаруживаем, что deepEquals возвращает true, а equals возвращает false. Это связано с тем, что deepEquals рекурсивно вызывает себя при обнаружении массива, а equals просто сравнивает ссылки подмассивов.

4.2. Многомерные массивы примитивных типов

Далее давайте проверим поведение с использованием многомерных массивов. В следующем примере два метода имеют разные выходные данные, что подчеркивает тот факт, что мы должны использовать deepEquals вместо метода equals при сравнении многомерных массивов:

    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. Многомерные массивы пользовательских объектов

Наконец, давайте проверим поведение методов 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;
        }
    }

Необходимо переопределить метод equals для нашего класса Person. В противном случае метод equals по умолчанию будет сравнивать только ссылки на объекты.

Кроме того, давайте учтем, что, хотя это и не относится к нашему примеру, мы всегда должны переопределять hashCode, когда переопределяем метод equals, чтобы не нарушать их контракты.

Далее мы можем сравнить два многомерных массива класса Person:

    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));

В результате рекурсивного сравнения подэлементов два метода снова дают разные результаты.

«Наконец, стоит упомянуть, что метод Objects.deepEquals внутренне выполняет метод Arrays.deepEquals, когда он вызывается с двумя массивами объектов:

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

5. Заключение

В этом кратком руководстве мы узнали, что мы должны используйте метод Arrays.deepEquals, когда мы хотим сравнить равенство между двумя вложенными или многомерными массивами объектов или примитивных типов.

Как всегда, полный исходный код статьи доступен на GitHub.