Java: как проверить равенство массивов?

Почему следующий код печатает "Different."?

boolean[][] a = { {false,true}, {true,false} };
boolean[][] b = { {false,true}, {true,false} };

if (Arrays.equals(a, b) || a == b)
    System.out.println("Equal.");
else
    System.out.println("Different.");

person user905686    schedule 08.11.2011    source источник
comment
Я всегда сначала проверял a == b или вообще не проверял. Если equals истинно, второе выражение всегда должно быть истинным.   -  person Peter Lawrey    schedule 08.11.2011
comment
Стандартная реализация в любом случае начинается с этой проверки, так что лично я бы ее пропустил.   -  person aioobe    schedule 08.11.2011
comment
Следует только указать, что оба дают ложь.   -  person user905686    schedule 08.11.2011
comment
@PeterLawrey на самом деле, вы имеете в виду, что если == верно, то equals должно быть верно.   -  person ealfonso    schedule 24.06.2015


Ответы (4)


Почему следующий код печатает "Different."?

Поскольку Arrays.equals выполняет поверхностное сравнение. Поскольку массивы наследуют свой equals-метод от Object, для внутренних массивов будет выполнено сравнение идентичности, которое завершится ошибкой, поскольку a и b не относятся к одним и тем же массивам.

Если вы измените на Arrays.deepEquals он напечатает "Equal.", как и ожидалось.

person aioobe    schedule 08.11.2011
comment
Документация говорит Array.equals: возвращает true, если два указанных массива объектов равны друг другу. Два массива считаются равными, если оба массива содержат одинаковое количество элементов и все соответствующие пары элементов в двух массивах равны. Так не означает ли это полное сравнение...? - person user905686; 08.11.2011
comment
Нет, потому что элементы a и b не equals(...) друг друга. Попробуйте сами: a[0].equals(b[0]) и вы увидите, что это ложь. - person aioobe; 08.11.2011
comment
Было бы лучше проверить a == b перед вызовом deepEquals, не так ли? - person Victor Sorokin; 08.11.2011
comment
Нет, было бы лучше вообще отказаться от этой избыточности. (Стандартная реализация Arrays.equals в любом случае начинается с этой проверки.) - person aioobe; 08.11.2011
comment
Обратите внимание, что Arrays.equals подходит для одномерных массивов: в этом примере Arrays.equals(a[0], b[0]) имеет значение true. - person Stephen Schaub; 02.06.2016

Это действительно не очевидно.

Прежде всего, оператор == просто сравнивает два указателя. Поскольку a и b — разные объекты, расположенные по разным адресам памяти, a == b вернет false (Эй, сторонники чистоты Java, я знаю, что == на самом деле сравнивает идентификаторы объектов. Я просто пытаюсь быть поучительным).

Теперь давайте взглянем на equals() реализацию массивов:

boolean[] c = new boolean[] { false, true, false };
boolean[] d = new boolean[] { false, true, false };

if (c.equals(d)) {
    System.out.println("Equals");
} else {
    System.out.println("Not equals");
}

Это напечатает Not equals, потому что ни один экземпляр массива фактически не реализует метод equals(). Итак, когда мы вызываем <somearray>.equals(<otherarray>), мы фактически вызываем метод Object.equals(), который просто сравнивает два указателя.

Тем не менее, обратите внимание, что ваш код на самом деле делает это:

boolean[] a0 = new boolean[] { false, true };
boolean[] a1 = new boolean[] { true, false };
boolean[] b0 = new boolean[] { false, true };
boolean[] b1 = new boolean[] { true, false };
boolean[][] a = new boolean[][] { a0, a1 };
boolean[][] b = new boolean[][] { b0, b1 };

if (Arrays.equals(a, b) || a == b)
    System.out.println("Equal.");
else
    System.out.println("Different.");

Arrays.equals(a, b) в конечном итоге вызовет a0.equals(b0), который вернет false. По этой причине Arrays.equals(a, b) также вернет false.

Таким образом, ваш код напечатает Different., и мы приходим к выводу, что равенство Java иногда может быть сложным.

person fernacolo    schedule 08.11.2011

Используйте Arrays.deepEquals() для многомерных массивов.

person MOleYArd    schedule 08.11.2011
comment
лол, это был ответ, который я очень долго искал - person Все Едно; 11.05.2017

person    schedule
comment
Не рекомендуется повторно реализовывать Arrays.deepEquals. Ответы, данные до сих пор, содержат хорошие объяснения и решения. - person user905686; 10.07.2012