Java Arrays.copyOf 产生浅拷贝还是深拷贝?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18351726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:48:30  来源:igfitidea点击:

Does Arrays.copyOf produce a shallow or a deep copy?

java

提问by Ingo Bürk

There seems to be a lot of confusion and different opinions on this out there ([1] and other sources) on whether Arrays.copyOfwill produce a deep or shallow copy.

关于是否Arrays.copyOf会产生深拷贝或浅拷贝,似乎有很多混淆和不同意见([1] 和其他来源)。

This test suggests that the copy is deep:

这个测试表明副本很深:

String[] sourceArray = new String[] { "Foo" };
String[] targetArray = java.util.Arrays.copyOf( sourceArray, 1 );

sourceArray[0] = "Bar";

assertThat( targetArray[0] ).isEqualTo( "Foo" ); // passes

This test suggests that the copy is shallow:

这个测试表明副本很浅:

String[][] sourceArray = new String[][] { new String[] { "Foo" } };
String[][] targetArray = java.util.Arrays.copyOf( sourceArray, 1 );

sourceArray[0][0] = "Bar";

assertThat( targetArray[0][0] ).isEqualTo( "Foo" ); // fails

Is the solution simply that a deep copy of the top-level dimension is made, but other dimensions are a shallow copy? What is the truth?

解决方案是不是简单地做一个顶层维度的深拷贝,而其他维度都是浅拷贝?真相是什么?

[1] How do I do a deep copy of a 2d array in Java?

[1]如何在 Java 中对二维数组进行深拷贝?

采纳答案by Thilo

It produces a shallow copy, i.e. a newarray that contains "old" references (to the same objects, those are not being copied).

它产生一个浅拷贝,即一个包含“旧”引用的数组(对相同的对象,那些没有被复制)。

In particular, if you have nested arrays, those will not be copied. You will just get a new array whose "top level" points to the same "second level" arrays as the original did. Any changes inside those nested arrays will be reflected in both copy and original.

特别是,如果您有嵌套数组,则不会复制这些数组。您将得到一个新数组,其“顶级”指向与原始数组相同的“二级”数组。这些嵌套数组内的任何更改都将反映在副本和原始数组中。

This test suggests that the copy is deep:

这个测试表明副本很深:

No, it does not. When you assign a new object to the "original" array, this does not affect the copy. It is, after all, a copy.

不,不是的。当您将新对象分配给“原始”数组时,这不会影响副本。毕竟,它是一个副本。

This is the same situation as:

这与以下情况相同:

String x = "foo";
String y = x;
x = "bar";

assertEquals(y, "foo");

No "deep copy" here.

这里没有“深拷贝”。

回答by xyz

Form Java Doc

形成Java 文档

....the two arrays will contain identical values.

....这两个数组将包含相同的值。

So in case of array containing reference, only reference is copied and not the actual object. Which means a shallow copy.

因此,在包含引用的数组的情况下,只会复制引用而不是实际对象。这意味着浅拷贝。

回答by otter

It is a deep copy. It appears shallow in the case of Strings because under the covers, Strings are Singletons. The JVM has a pool of memory for Strings and makes only one copy of each unique string. So you always get a copy of the reference to that string. The example below shows that a deep copy is made for the class Object. When the original array is changed, the copy does not change.

这是一个深拷贝。在字符串的情况下它看起来很浅,因为在幕后,字符串是单例。JVM 有一个用于字符串的内存池,并且只为每个唯一的字符串制作一个副本。因此,您始终会获得对该字符串的引用副本。下面的示例显示为类 Object 制作了一个深拷贝。当原始数组改变时,副本不会改变。

public class ArrayTest {

公共类 ArrayTest {

public static void main(String [] args) {
    Object [] objs = new Object[1];
    objs[0] = new Object();
    System.out.println("Original: " + objs[0].toString());

    Object [] copy = java.util.Arrays.copyOf(objs, 1);
    objs[0] = new Object();
    System.out.println("copy, after original reassigned: " +
    copy[0].toString());
    System.out.println("Original, after reassigned: " +
    objs[0].toString());
}

}

}

回答by Trunk

'Shallow' or 'deep' - and this is a matter that I see no one defining precisely - the method Arrays.copyOf(..)DOES in practice produce a copy of the source array which remains unaffected by changes to the source array.

“浅”或“深”——这是我看不到任何人精确定义的问题——该方法Arrays.copyOf(..)在实践中确实会生成源数组的副本,该副本不受源数组更改的影响。

Take the following simple example with int arrays:

以以下带有 int 数组的简单示例为例:

import java.util.Arrays;

public class DeepCopyTest
{

    public static void main(String[] args)
    {
       int[] source = { 1, 2, 3, 4, 5, 6};
       int[] target = new int[source.length];
       // Copy target from source via Arrays.copyOf(..) method :
       target = Arrays.copyOf(source, 6);
       // Check for equality :
       System.out.println("Source1 : " + Arrays.toString(source));
       System.out.println("Target1 : " + Arrays.toString(target));
       // Increment all entries in source array :
       for(int i = 0; i < source.length; i++)
       {
          source[i] = source[i] +1;
       }
       // See if target is affected :
       System.out.println("Source2 : " + Arrays.toString(source));
       System.out.println("Target2 : " + Arrays.toString(target));

    }

}

// OUTPUT
// ------
Source1 : [1, 2, 3, 4, 5, 6]
Target1 : [1, 2, 3, 4, 5, 6]
Source2 : [2, 3, 4, 5, 6, 7]
Target2 : [1, 2, 3, 4, 5, 6]

In practice, when people seek a "deep copy" of an array, they merely want something that is unaffected by changes to the original.

在实践中,当人们寻找数组的“深层副本”时,他们只是想要一些不受原始更改影响的东西。

And this Arrays.copyOf(..)` method does give them this.

而这个 Arrays.copyOf(..)` 方法确实给了他们这个。

As well as primitive type arrays, String object arrays also behave as the above example, giving output like :

除了原始类型数组,String 对象数组的行为也与上面的示例相同,输出如下:

Source1 : [a, b, c, d, e, f]
Target1 : [a, b, c, d, e, f]
Source2 : [a1, b1, c1, d1, e1, f1]
Target2 : [a, b, c, d, e, f]

when the initial source array entries are concatenated by "1".

当初始源数组条目由“1”连接时。

It also 'works' for Object arrays in the sense that the target is no longer tied to the source when the latter is reassigned. BUT looking at the output for the first element of both arrays after copying and then after altering source[0] reveals the full truth :

它也适用于对象数组,因为当后者被重新分配时,目标不再与源绑定。但是在复制后查看两个数组的第一个元素的输出,然后在更改 source[0] 后,揭示了全部真相:

Source1 : java.lang.Object@1db9742
Target1 : java.lang.Object@1db9742
Source2 : java.lang.Object@106d69c
Target2 : java.lang.Object@1db9742

After the original source array is copied, the target elements simply have been pointed to whatever values are currently held in their source counterparts. For target[0] it is the contents of memory address 1db9742 -- which is also the the same memory address holding source[0] . . . .

在原始源数组被复制后,目标元素只是被指向了当前在它们的源对应物中保存的任何值。对于 target[0],它是内存地址 1db9742 的内容——这也是保存 source[0] 的相同内存地址。. . .

And the reason we get a debonding between source and target after source[0] is reassigned is due to the fact that the assignment statement

在重新分配 source[0] 后,我们在源和目标之间分离的原因是由于赋值语句

source[0] = new Object();

simply causes the memory reference held in source[0] to be changed to some new location as a new Object is being pointed at. So it is not after all a true deep copy in the pure sense, even though in many cases it gives the coder the same benefits as a deep copy.

当指向一个新对象时,简单地导致保存在 source[0] 中的内存引用被更改到某个新位置。因此,它毕竟不是纯粹意义上的真正深拷贝,尽管在许多情况下它为编码人员提供了与深拷贝相同的好处。

With arrays of primitive data the Arrays.copyOf(..) method can't copy references as these are not used for primitives. It just copies the source element values into the target elements. Again we have the same effect as a deep copy at the expense of an operation needing much less code than for a deep copy.

对于原始数据数组, Arrays.copyOf(..) 方法不能复制引用,因为这些不用于原始数据。它只是将源元素值复制到目标元素中。同样,我们具有与深拷贝相同的效果,但代价是操作所需的代码比深拷贝少得多。

So Arrays.copyOf(..) is a 'cheap' deep copy for both primitive and 1-D Object arrays. But any data array more complex and it is found out.

所以 Arrays.copyOf(..) 是原始数组和一维对象数组的“廉价”深拷贝。但任何数据数组更复杂,它被发现。

Maybe it should be called a semi-deep copy.

也许它应该被称为半深拷贝。

回答by Prashant Shingne

It create Shallow copy because but since java uses parameter by value the copies of all the variable is available in cloned object however for reference type variable copy of address is created and points to same object which is referred by original array so when copied object is modified original object in array also get updated. see the code below.

它创建浅拷贝,因为但是由于 java 按值使用参数,因此所有变量的副本都可以在克隆对象中使用,但是对于引用类型的地址变量副本被创建并指向由原始数组引用的同一对象,因此当复制对象被修改时数组中的原始对象也得到更新。请参阅下面的代码。

import java.util.*;
import java.lang.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */
class ArraysCopyOfDemo
{
    public static void main (String[] args) throws java.lang.Exception
    {
        Object[] originalArray= new Object[1];
        Employee e1= new Employee("Salman","Khan");
        originalArray[0]=e1;
        System.out.println("Original Array content printed ");
        printArray(originalArray);

      Object[] copiedArray=originalArray.clone();
        System.out.println("Copied Array content printed ");
        printArray(copiedArray);
        System.out.println("Copied Array content modified ");
        Employee CopiedEmp1= (Employee)copiedArray[0];
        CopiedEmp1.setFirstname("Amir");
        System.out.println("Copied Array content printed ");
        printArray(copiedArray);
        System.out.println("Original Array content printed to verify shallow copy or deep copy");
        printArray(originalArray);
    }
    private static void printArray(Object[] arrays ){
        for(Object emp:arrays){
            System.out.print(((Employee)emp).getFirstname() + " ");
            System.out.print(((Employee)emp).getLastname());
            System.out.println();
        }
    }
}
class Employee implements Cloneable{
    private String firstname;
    private String lastname;
    public Employee(String firstname,String lastname){
        this.firstname=firstname;
        this.lastname=lastname;
    }
    public String getFirstname(){
       return firstname;
    }
    public String getLastname(){
        return lastname;
    }
    public void setFirstname(String firstname){
        this.firstname=firstname;
    }
     public void setLirstname(String lastname){
         this.lastname=lastname;
    }

}

O/p
Original Array content printed 
Salman Khan
Copied Array content printed 
Salman Khan
Copied Array content modified 
Copied Array content printed 
Amir Khan
Original Array content printed to verify shallow copy or deep copy
Amir Khan