Как клонировать многомерный массив в java?

Изменить 2: Ниже приведен фрагмент кода на основе ответа DuffyMo, который иллюстрирует, как обойти ограничения клонирования для многомерных массивов с использованием System.arraycopy.

import java.util.Arrays;

public class Randar {
public static int[][] arrayMaster = {{6,1}, {10,1}, {1,1}};
private static int[][] arrayChanges = new int[arrayMaster.length][2];

public Randar () {

}
public static void main(String[] args) {
    arrayChanges[0][0] = 0;
    resetArrays(arrayChanges, arrayMaster);
    arrayChanges[0][0] = 0;

    System.out.format("arrayMaster: %s, arrayChanges: %s", Arrays.deepToString(arrayMaster), Arrays.deepToString(arrayChanges));
}


public static void resetArrays(int[][] arrayChanges, int[][] arrayMaster) {
for (int a=0; a< arrayMaster.length; a++) {
System.arraycopy(arrayMaster[a], 0, arrayChanges[a], 0, arrayMaster[a].length);
}
// arrayChanges = arrayMaster.clone(); will NOT work as expected
}
}

[ОРИГИНАЛЬНЫЙ ВОПРОС] Какой простой способ (полностью) клонировать многомерный массив в java? Эта программа иллюстрирует мою проблему.

import java.util.Arrays;

public class Randar {
public static int[][] arrayMaster = {{6,1}, {10,1}, {1,1}};
static private int[][] arrayChanges = arrayMaster;

public static void main(String[] args) {
    arrayChanges[0][0] = 0;
    resetArrays();

    System.out.format("arrayMaster: %s, arrayChanges: %s",Arrays.deepToString(arrayMaster), Arrays.deepToString(arrayChanges));
}


public static void resetArrays() {
arrayChanges = arrayMaster.clone();
}

}

При запуске вышеуказанного кода arrayMaster изменяется, а также arrayChanges, в отличие от моих намерений. Думая, что я могу клонировать каждый отдельный элемент массива arrayMaster, я попытался обойти проблему с этим:

for (int iter = 0; iter < arrayMaster.length; iter++) {
    arrayChanges[iter] = arrayMaster[iter].clone();
    }

но когда я запускаю код, который по какой-то причине дает исключение NullPointerException. Является ли запись метода, который меняет только отдельные значения массивов в моем массиве?

Спасибо.

РЕДАКТИРОВАТЬ 1: Это также не устраняет проблему.

import java.util.Arrays;

public class Randar {
public int[][] arrayMaster = {{6,1}, {10,1}, {1,1}};
private int[][] arrayChanges = arrayMaster.clone();

public Randar () {

}
public static void main(String[] args) {
    Randar Randar1 = new Randar();
    Randar1.arrayChanges[0][0] = 0;
    resetArrays(Randar1.arrayChanges, Randar1.arrayMaster);
    Randar1.arrayChanges[0][0] = 0;

    System.out.format("arrayMaster: %s, arrayChanges: %s",     Arrays.deepToString(Randar1.arrayMaster), Arrays.deepToString(Randar1.arrayChanges));
}


public static void resetArrays(int[][] arrayChanges, int[][] arrayMaster) {
/*for (int a=0; a< arrayMaster.length; a++) {
System.arraycopy(arrayMaster[a].clone(), 0, arrayChanges[a], 0, arrayMaster[a].length);
} */
arrayChanges = arrayMaster.clone();
}
}

Ответ 1

При запуске вышеуказанного кода arrayMaster изменяется, а также arrayChanges, в отличие от моих намерений.

Линия

static private int[][] arrayChanges = arrayMaster;

является виновником. В этой строке arrayChanges и arrayMaster указывают на один и тот же объект, поэтому при доступе к объекту из одного и того же объекта видится одно или другое.

EDIT: что происходит, когда вы клонируете одно измерение многомерного массива

Как объясняет Эрик Липперт, массив концептуально представляет собой список переменных. Если вы просто назначили другую переменную, указывающую на тот же массив a la static private int[][] arrayChanges = arrayMaster;, вы вообще не изменили набор переменных. Вы не создали никаких новых переменных, кроме arrayChanges, поэтому вы не получили больше памяти из операционной системы /JVM, поэтому любое изменение, которое вы делаете на arrayMaster, применяется к arrayChanges и наоборот.

Теперь посмотрим на двумерный массив. В Java двумерный массив представляет собой список переменных, которые имеют свойство, которое каждая из этих переменных относится к одномерному массиву. Таким образом, всякий раз, когда вы клонируете двумерный массив, вы создаете новый список переменных, каждый из которых указывает на то же место, в котором указывали старые переменные. Итак, вы немного набрали, что можете спокойно писать arrayChanges[0] = new int[10], не затрагивая arrayMaster, но как только вы начнете ссылаться на arrayChanges[i][j], вы все равно ссылаетесь на те же массивы второго уровня, что и ссылки arrayMaster. То, что вы действительно хотите для глубокого копирования двумерного массива ints, это

public static int[][] deepCopyIntMatrix(int[][] input) {
    if (input == null)
        return null;
    int[][] result = new int[input.length][];
    for (int r = 0; r < input.length; r++) {
        result[r] = input[r].clone();
    }
    return result;
}

Тем, кто может взглянуть на этот ответ в будущем: да, лучше заменить int на T здесь и сделать метод общим, но для этого более конкретный метод глубокой копии проще объяснить хорошо.

Ответ 2

clone выполняет "мелкую" копию. То есть внешний массив дублируется, но сохраненные в нем значения не изменяются. Поэтому, если у вас есть A1 = {B1, B2, B3} и клонировать то, что в A2, исходное содержимое A2 будет {B1, B2, B3}. Если вы измените A1 на {C1, B2, B3}, то A2 останется неизменным, но если вы измените содержимое B1 (без его замены), то A2 "увидит" это изменение.

Чтобы выполнить то, что вы хотите, вы должны пройти через внешний массив и clone элементы этого внешнего массива (которые являются внутренними массивами).

Pidgin Java:

int[][] A2 = A1.clone();
for (int i = 0; i < A2.length; i++) {
    A2[i] = A2[i].clone();
}