Java Arrays.equals() возвращает false для двухмерных массивов

Мне было просто интересно узнать - почему Arrays.equals(double [] [], double [] []) возвращает false? когда на самом деле массивы имеют одинаковое количество элементов, и каждый элемент один и тот же?

Например, я выполнил следующий тест.

double[][] a,  b;
int size =5;

a=new double[size][size];
b=new double[size][size];

for( int i = 0; i < size; i++ )
    for( int j = 0; j < size; j++ ) {
        a[i][j]=1.0;
        b[i][j]=1.0;
    }

if(Arrays.equals(a, b))
    System.out.println("Equal");
else
    System.out.println("Not-equal");

Возвращает false и печатает "Неравномерно".

с другой стороны, если у меня есть что-то вроде этого:

double[] a,  b;
int size =5;

a=new double[size];
b=new double[size];

for( int i = 0; i < size; i++ ){
    a[i]=1.0;
    b[i]=1.0;
} 

if(Arrays.equals(a, b))
    System.out.println("Equal");
else
    System.out.println("Not-equal");

возвращает true и печатает "Equal". Работает ли этот метод только с отдельными измерениями? если да, то что-то подобное для многомерных массивов в Java?

Ответ 1

Используйте deepEquals(Object[], Object[]).

Возвращает true, если два указанных массива глубоко равны друг другу.

Так как a int[] является instanceof Object, a int[][] является instanceof Object[].


Что касается того, почему Arrays.equals не работает для двухмерных массивов, его можно объяснить шаг за шагом следующим образом:

Для массивов equals определяется в терминах идентичности объекта

System.out.println(
    (new int[] {1,2}).equals(new int[] {1,2})
); // prints "false"

Это потому, что массивы наследуют их equals от их общего суперкласса, Object.

Часто нам действительно нужно равенство значений для массивов, и именно поэтому java.util.Arrays предоставляет утилиту static equals(int[], int[]).

System.out.println(
    java.util.Arrays.equals(
        new int[] {1,2},
        new int[] {1,2}
    )
); // prints "true"

Массив массивов в Java

  • An int[] является instanceof Object
  • An int[][] - это instanceof Object[]
  • int[][] НЕ a instanceof int[]

В Java нет двухмерных массивов. Он даже не имеет многомерных массивов. Java имеет массив массивов.

java.util.Arrays.equals является "мелким"

Теперь рассмотрим этот фрагмент:

System.out.println(
    java.util.Arrays.equals(
        new int[][] {
            { 1 },
            { 2, 3 },
        },
        new int[][] {
            { 1 },
            { 2, 3 },
        }
    )
); // prints "false"

Вот факты:

  • Каждый аргумент Object[]
    • Элемент с индексом 0 является int[] { 1 }
    • Элемент с индексом 1 является int[] { 2, 3 }.
  • Есть два экземпляра Object[]
  • Есть четыре экземпляра int[]

Из предыдущей точки должно быть ясно, что это вызывает перегрузку Arrays.equals(Object[], Object[]). Из API:

Возвращает true, если два указанных массива Objects равны друг другу. Два массива считаются equal, если оба массива содержат одинаковое количество элементов, а все соответствующие пары элементов в двух массивах равны. Два объекта e1 и e2 считаются равными, если (e1==null ? e2==null : e1.equals(e2)).

Теперь должно быть понятно, почему вышеприведенный фрагмент печатает "false"; потому что элементы массива Object[] не равны указанному выше определению (поскольку int[] имеет свой equals, определяемый идентификатором объекта).

java.util.Arrays.deepEquals является "глубоким"

Напротив, здесь Arrays.deepEquals(Object[], Object[]):

Возвращает true, если два указанных массива глубоко равны друг другу. В отличие от метода equals(Object[],Object[]), этот метод подходит для использования с вложенными массивами произвольной глубины.

System.out.println(
    java.util.Arrays.deepEquals(
        new int[][] {
            { 1 },
            { 2, 3 },
        },
        new int[][] {
            { 1 },
            { 2, 3 },
        }
    )
); // prints "true"

Вкл Arrays.toString и Arrays.deepToString

Стоит отметить аналогию между этими двумя методами и то, что мы обсуждали до сих пор в отношении вложенных массивов.

System.out.println(
    java.util.Arrays.toString(
        new int[][] {
            { 1 },
            { 2, 3 },
        }
    )
); // prints "[[[email protected], [[email protected]]"

System.out.println(
    java.util.Arrays.deepToString(
        new int[][] {
            { 1 },
            { 2, 3 },
        }
    )
); // prints "[[1], [2, 3]]"

Опять же, рассуждение аналогично: Arrays.toString(Object[]) рассматривает каждый элемент как Object и просто вызывает его метод toString(). Массивы наследуют свой toString() из своего общего суперкласса Object.

Если вы хотите, чтобы java.util.Arrays рассматривал вложенные массивы, вам нужно использовать deepToString, как вам нужно использовать deepEquals.

Ответ 2

java фактически не имеет многомерных массивов. Вместо этого он имеет только одномерный массив, а массивы multi d будут массивами этих 1d-массивов. String.equals() может выполняться только для базовых одноблочных массивов и, следовательно, не работает для многомерных измерений.