Перейти к основному содержимому

Массивы.deepEquals

· 5 мин. чтения

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 , если оба параметра равны нулю
  • false , если только один из двух параметров имеет значение null
  • false , если массивы имеют разную длину
  • true , если оба массива пусты
  • true , если массивы содержат одинаковое количество элементов и каждая пара подэлементов глубоко равна
  • ложно в других случаях

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

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

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

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 .