如何在java中克隆多维数组?

2022-09-03 04:00:30

编辑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会更改数组更改,这与我的意图相反。考虑到我可以克隆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会更改数组更改,这与我的意图相反。

生产线

static private int[][] arrayChanges = arrayMaster;

是罪魁祸首。此行使并指向同一对象,因此当您从任一对象访问对象时,对任何一个对象的更改都是可见的。arrayChangesarrayMaster

编辑:每当您克隆多维数组的一个维度时会发生什么

正如 Eric Lippert 所解释的那样,数组在概念上是变量列表。如果你只是分配另一个变量来指向同一数组 a la ,你根本没有改变变量集。除了 之外,您没有创建任何新变量,因此您没有从操作系统/JVM 获得更多内存,因此您所做的任何更改都将应用于,反之亦然。static private int[][] arrayChanges = arrayMaster;arrayChangesarrayMasterarrayChanges

现在让我们看一个二维数组。在Java中,二维数组是一个变量列表,这些变量恰好具有这些变量中的每一个都引用一维数组的属性。因此,每当您克隆二维数组时,都会创建一个新的变量列表,每个变量都指向旧变量指向的同一位置。因此,您已经获得了一些好处,因为您可以安全地编写而不会影响 ,但是一旦您开始引用,您仍然在引用与引用的相同的二级数组。为了深度复制一个二维的int数组,你真正想要的是arrayChanges[0] = new int[10]arrayMasterarrayChanges[i][j]arrayMaster

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;
}

对于那些将来可能会看到这个答案的人来说:是的,最好用这里代替并使方法通用,但是为此目的,更具体的深度复制方法更容易解释。intT


答案 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();
}