为什么array.copyof()在使用2d数组时会改变原始数组?

qvsjd97n  于 2021-06-29  发布在  Java
关注(0)|答案(2)|浏览(305)

如果我创建一个2d int 数组,然后使用 Arrays.copyOf() ,就像这样-

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() ,则只为最外层的数组创建单独的副本,而每个内部数组仍然是对原始二维数组的内部数组的引用?

jshell> d1 = null
d1 ==> null

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

如果是,为什么是这样?不应该 Arrays.copyOf() 创建不同的副本,至少每个文档?oracle文档中是否记录了这种行为?
最后,用同样的方法创建二维数组的不同副本的正确方法是什么 Arrays.copyOf() 适用于1d阵列?

mxg2im7a

mxg2im7a1#

方法 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); }
    }
}
3phpmpom

3phpmpom2#

2d数组基本上是包含数组的数组,并且 Arrays.copyOf 执行浅层复制,因此只复制外部数组(数组的数组),而不复制数组内部的值(在本例中,是数组的数组) int ,即 int[] ). 因此,原件和复印件都包含相同的内容 int[] 数组,因此如果通过一个数组进行修改,结果也可以通过另一个数组看到。
javadoc中明确提到了这一点:
对于在原始数组和副本中都有效的所有索引,这两个数组将包含相同的值。
你需要在知道签名的情况下阅读: <T> T[] copyOf(T[], int) . 已复制阵列 T[] (一组 T ,在哪里 Tint[] ),不是 T[][] !
对于2d数组的深度复制,您必须自己进行深度复制,例如,请参阅如何在java中进行2d数组的深度复制?

相关问题