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 .