16

编辑 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();
}
}
4

2 回答 2

21

运行上述代码时,arrayMaster 和 arrayChanges 都发生了变化,这与我的意图相反。

线

static private int[][] arrayChanges = arrayMaster;

是罪魁祸首。这条线生成arrayChangesarrayMaster指向同一个对象,因此当您从任一对象访问对象时,对任一对象的更改都是可见的。

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

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

现在让我们看一个二维数组。在 Java 中,二维数组是一个变量列表,这些变量恰好具有这些变量中的每一个都引用一维数组的属性。所以,每当你克隆一个二维数组时,你都会创建一个新的变量列表,每个变量都指向旧变量指向的同一个位置。所以,你已经获得了一点,你可以安全地编写arrayChanges[0] = new int[10]而不影响arrayMaster,但是一旦您开始引用arrayChanges[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此处替换并使该方法通用,但为此目的,更具体的深层复制方法更易于解释。

于 2012-02-02T02:06:23.263 回答
20

clone做一个“浅”的复制。也就是说,最外面的数组是重复的,但其中存储的值不变。所以如果你有 A1 = { B1, B2, B3 } 并将其克隆到 A2 中,A2 的初始内容将是 { B1, B2, B3 }。如果您将 A1 更改为 { C1, B2, B3 } 那么 A2 将保持不变,但如果您更改 B1 的内容(不替换它),那么 A2 将“看到”该更改。

要完成您想要的,您必须遍历外部数组和clone该外部数组的元素(它们是内部数组)。

洋泾浜Java:

int[][] A2 = A1.clone();
for (int i = 0; i < A2.length; i++) {
    A2[i] = A2[i].clone();
}
于 2012-02-02T03:08:49.890 回答