通过Arrays.copyOf()生成的二维数组副本中的更改反映在原始数组中



如果我用Java创建一个2Dint数组,然后使用Arrays.copyOf()复制它,就像so-

jshell> int[][] c1 = {{1,2}, {3,4}}
c1 ==> int[2][] { int[2] { 1, 2 }, int[2] { 3, 4 } }
jshell> int[][] d1 = Arrays.copyOf(c1, c1.length)
d1 ==> int[2][] { int[2] { 1, 2 }, int[2] { 3, 4 } }

如果我更改了副本中的一个元素,为什么原始2D阵列中的相应单元会在这个过程中发生突变?

jshell> d1[0][0] = 0
$21 ==> 0
jshell> d1
d1 ==> int[2][] { int[2] { 0, 2 }, int[2] { 3, 4 } }
jshell> c1
c1 ==> int[2][] { int[2] { 0, 2 }, int[2] { 3, 4 } } // c1[0][0] was 1 originally

这让我相信,在使用Arrays.copyOf()复制2D阵列的过程中,只为最外层的阵列创建一个单独的副本,而每个内部阵列仍然是原始2D阵列的内部阵列的引用?

jshell> d1 = null
d1 ==> null
jshell> c1
c1 ==> int[2][] { int[2] { 0, 2 }, int[2] { 3, 4 } }

如果是,为什么会这样?Arrays.copyOf()不应该创建不同的副本吗?至少根据文档是这样吗?Oracle文档中是否记录了这种行为?

最后,创建2D阵列的不同副本的正确方法是什么,就像Arrays.copyOf()用于1D阵列一样?

2D数组基本上是一个包含数组的数组,而Arrays.copyOf执行浅层复制,因此只复制外部数组(数组的数组(,而不复制数组内部的值(在这种情况下,是int的数组,即int[]的数组(。因此,原始数组和副本都包含相同的int[]数组,因此,如果通过其中一个进行修改,则通过另一个也可以看到结果。

javadoc:中明确提到了这一点

对于在原始数组和复制时,两个数组将包含相同的值。

您确实需要在了解签名<T> T[] copyOf(T[], int)的情况下阅读。复制的数组是T[](T的数组,其中Tint[](,而不是T[][]

对于2D阵列的深度复制,您必须自己深度复制阵列,例如,请参阅如何在Java中进行2D阵列的深层复制?

方法Arrays.copyOf不执行数组的深度复制System.arraycopy方法也不执行。您应该用所需的复制深度自己实现数组的深度复制的算法。例如:

int[][] arr1 = {{1, 2}, {3, 4}};                 // original array
int[][] arr2 = Arrays.copyOf(arr1, arr1.length); // shallow copy
int[][] arr3 = Arrays.stream(arr1)               // deep copy
.map(Arrays::stream)
.map(IntStream::toArray)
.toArray(int[][]::new);
arr1[0][0] = 7;
System.out.println(Arrays.deepToString(arr1)); // [[7, 2], [3, 4]]
System.out.println(Arrays.deepToString(arr2)); // [[7, 2], [3, 4]]
System.out.println(Arrays.deepToString(arr3)); // [[1, 2], [3, 4]]

对象数组也是如此:

public class Test {
public static void main(String[] args) {
SomeObject[] arr1 = {                                 // original array
new SomeObject(1),
new SomeObject(2),
new SomeObject(3),
new SomeObject(4)};
SomeObject[] arr2 = Arrays.copyOf(arr1, arr1.length); // shallow copy
SomeObject[] arr3 = Arrays.stream(arr1)               // deep copy
.mapToInt(SomeObject::getField)
.mapToObj(SomeObject::new)
.toArray(SomeObject[]::new);
arr1[0].setField(7);
System.out.println(Arrays.toString(arr1)); // [7, 2, 3, 4]
System.out.println(Arrays.toString(arr2)); // [7, 2, 3, 4]
System.out.println(Arrays.toString(arr3)); // [1, 2, 3, 4]
}
static class SomeObject {
int field;
public SomeObject(int field) { this.field = field; }
public int getField() { return field; }
public void setField(int field) { this.field = field; }
public String toString() { return String.valueOf(field); }
}
}

最新更新