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

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?


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.


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.


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