微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

如果我在 Java 中创建一个 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,4 } }

如果我随后更改了副本中的一个元素,为什么原始二维数组中的相应单元格会在此过程中发生变异?

jshell> d1[0][0] = 0
$21 ==> 0

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

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

这让我相信在使用 Arrays.copyOf() 复制二维数组时,只会为最外层数组创建一个单独的副本,而每个内部数组仍然是对原始二维数组的内部数组的引用?

jshell> d1 = null
d1 ==> null

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

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

最后,创建二维数组的不同副本的正确方法是什么,就像 Arrays.copyOf() 用于一维数组一样?

解决方法

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

javadoc 中明确提到了这一点:

对于在原始数组和数组中都有效的所有索引 复制,两个数组将包含相同的值。

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

对于二维数组的深拷贝,你必须自己深拷贝数组,例如见How do I do a deep copy of a 2d array in Java?

,

方法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,4]]
System.out.println(Arrays.deepToString(arr3)); // [[1,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,4]
        System.out.println(Arrays.toString(arr3)); // [1,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); }
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?