Reputation: 20043
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?
Upvotes: 22
Views: 22888
Reputation: 11
It's a straightforward shallow copy using = operator
Confusion comes if you change the referenced object of any of them the other variable will still contain the old reference to the old object.
While if you modify the object itself it will be changed in both variables.
var car1=new car(1);
var car2=car1;
car1=new car(2);
//car1.id=2 ,car2.id=1;
var car1=new car(1);
var car2=car1;
car1.id=2
//car1.id=2 ,car2.id=2;
Upvotes: 1
Reputation: 11
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
Upvotes: 1
Reputation: 756
'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.
Upvotes: 5
Reputation: 21
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());
}
}
Upvotes: -5
Reputation: 22720
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.
Upvotes: 8
Reputation: 262724
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.
Upvotes: 31