Does Arrays.copyOf produce a shallow or a deep cop

2020-01-27 07:41发布

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

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?

标签: java
5条回答
▲ chillily
2楼-- · 2020-01-27 08:01

It produces a shallow copy, i.e. a new array 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.

查看更多
Rolldiameter
3楼-- · 2020-01-27 08:01

'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.

Take the following simple example with int arrays:

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.

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

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".

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 :

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] . . . .

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] = 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.

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.

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.

Maybe it should be called a semi-deep copy.

查看更多
The star\"
4楼-- · 2020-01-27 08:07

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.

public class 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());
}

}

查看更多
劳资没心,怎么记你
5楼-- · 2020-01-27 08:16

Form Java Doc

....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.

查看更多
Ridiculous、
6楼-- · 2020-01-27 08:22

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.

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
查看更多
登录 后发表回答