I am trying to understand the concept of shallow vs deep copy in Java. There is a lot of articles and Q&A about this subject, but whenever I try to implement these concepts in a real Java code, everything become unclear to me.
One of the answers on which I base my understanding is in this link, where deep and shallow copying are explained via schemas.
I will show you below my implementation for each case:
I took for my example the method System.arraycopy() as I read in many articles that it performs a shallow copy (along with the clone method)
public class Test {
public static void main(String[] args) {
NameValue[] instance1 = {
new NameValue("name1", 1),
new NameValue("name2", 2),
new NameValue("name3", 3),
};
NameValue[] instance2 = new NameValue[instance1.length];
// Print initial state
System.out.println("Arrays before shallow copy:");
System.out.println("Instance 1: " + Arrays.toString(instance1));
System.out.println("Instance 2: " + Arrays.toString(instance2));
// Perform shallow copy
System.arraycopy(instance1, 0, instance2, 0, 3);
// Change instance 1
for (int i = 0; i < 3; i++) {
instance1[i].change();
}
// Print final state
System.out.println("Arrays after shallow copy:");
System.out.println("Instance 1: " + Arrays.toString(instance1));
System.out.println("Instance 2: " + Arrays.toString(instance2));
}
private static class NameValue {
private String name;
private int value;
public NameValue(String name, int value) {
super();
this.name = name;
this.value = value;
}
public void change() {
this.name = this.name + "-bis";
this.value = this.value + 1;
}
@Override
public String toString() {
return this.name + ": " + this.value;
}
}
}
The result of the execution of the main methods is as follows:
Arrays before shallow copy:
Instance 1: [name1: 1, name2: 2, name3: 3]
Instance 2: [null, null, null]
Arrays after shallow copy:
Instance 1: [name1-bis: 2, name2-bis: 3, name3-bis: 4]
Instance 2: [name1-bis: 2, name2-bis: 3, name3-bis: 4]
this result is an accordance with the schema of the previous link:
I took for this example the method Arrays.copyOf() as I read in many articles that it performs a deep copy (along with the Arrays.copyOfRange method)
public static void main(String[] args) {
NameValue[] instance1 = {
new NameValue("name1", 1),
new NameValue("name2", 2),
new NameValue("name3", 3),
};
NameValue[] instance2 = new NameValue[instance1.length];
// Print initial state
System.out.println("Arrays before deep copy:");
System.out.println("Instance 1: " + Arrays.toString(instance1));
System.out.println("Instance 2: " + Arrays.toString(instance2));
// Perform deep copy
instance2 = Arrays.copyOf(instance1, 3);
// Change instance 1
for (int i = 0; i < 3; i++) {
instance2[i].change();
}
// Print final state
System.out.println("Arrays after deep copy:");
System.out.println("Instance 1: " + Arrays.toString(instance1));
System.out.println("Instance 2: " + Arrays.toString(instance2));
}
which displays:
Arrays before deep copy:
Instance 1: [name1: 1, name2: 2, name3: 3]
Instance 2: [null, null, null]
Arrays after deep copy:
Instance 1: [name1-bis: 2, name2-bis: 3, name3-bis: 4]
Instance 2: [name1-bis: 2, name2-bis: 3, name3-bis: 4]
If we base the deep copy logic on the previous schema, this should be the result:
As you may notice, the result of the execution of the main method is different from the logic of the schema above.
Any explanation will be welcome.
I don't know where you read that copyOf()
performs a deep copy, because that is just plain wrong.
Quoting javadoc of Arrays.copyOf(T[] original, int newLength)
:
For all indices that are valid in both the original array and the copy, the two arrays will contain identical values.
That means it's a shallow copy. To be a deep copy, the values would have to point to different objects, since the referenced object would have to be a copy too.
To perform a deep copy, you have to iterate the array and copy the values. Java can't do that for you, because it doesn't know how to copy the object.
E.g. how would Java know how to copy a NameValue
object? clone()
? Copy constructor? Serialize+Deserialize? Factory method? Other means?
I am trying to understand the concept of shallow vs deep copy in Java.
In Java you pass around and store references to objects not the objects themselves.
So when you have an NameValue[] array
the array does not contain the objects NameValue
but references to the objects.
So when you do a shallow copy to NameValue[] array2
it means you are just copying the references from one array to the other. Which effectively means that now both array
and array2
refer to exactly the same objects and any change you do from array[2]
will be visible from array2[2]
(same object).
When you deep copies you copy each object completely to another memory area and you keep a reference to that new object in your new array.
This way the 2 arrays now refer to different objects and any change to array[2]
are not visible from array2[2]
Update:
This does not apply to primitives that do store the actual value and not a reference.
So an int[] a
when you copy you get a copy of the values (i.e. deep copy in a sense) because a[2]
contains the value itself and not the reference to the value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With