This post will discuss shallow copy and deep copy in Java in detail with examples.

Shallow Copy

In Java, java.lang.Object provides clone() method, which is widely used to create copy of the object. The default implementation Object.clone() method returns an exact copy of the original object. It does that by field-by-field assignment of primitive, mutable, and immutable types. In other words, Object.clone() creates a new object of the same run-time type as the original object, and for every primitive, mutable, and immutable field, it performs newObj.field = obj.field operation, where newObj and obj are the new object and original object, respectively.

This works fine if the class contains only primitives and immutable fields. But field-by-field assignment will not result in desired behavior if any mutable fields such as collections and arrays are present in the class since memory would be shared between the original and the copy. As referenced objects are shared, if one of either object is modified, the change is visible in the other. This is nothing but a shallow copy, where object references get copied and not the referred objects themselves.

Shallow Copy

Download  Run Code

Output:

Cloned Object: [Jon Snow, 22, [Maths, English, Science, History]]

Shallow Copy
Shallow Copy

{Jon Snow=22, John Cena=40}

Deep Copy

An alternative to shallow copy is a deep copy, where new objects are created for any referenced objects rather than references to objects being copied.

The JDK provides no deep-copy equivalent to Object.clone() method. But we can achieve deep copy by modifying the default implementation of the Object.clone() method and allocate new memory for mutable fields of the object returned by super.clone() before returning to the caller. If the object has any references to other objects as fields, it is recommended to call the clone() method on them. Primitive fields can be ignored, as their content is already copied. For immutable fields like string, we can let the method copy the reference, and both the original and its clone will share the same object. Now any changes made to the cloned object will not be reflected in an original object or vice-versa.

Deep Copy

Download  Run Code

Output:

Cloned Object: [Jon Snow, 22, [Maths, English, Science, History]]

Deep Copy
Deep Copy
{Jon Snow=22}

 
The Object.clone() method will result in a compilation error if we try to assign a value to a final field. The solution to address this problem is to use serialization and deserialization, which is relatively easier to implement Object.clone() as a deep copy can be several levels deep and error-prone for complex graph objects if done manually. Apache Commons Lang also provides an implementation of the clone() method. It also performs deep cloning using serialization. The implementation can be seen here. Please note that Serialization will be very slow and does not clone transient fields. We can also use Copy Constructor if the object is not too complex.

Differences between Shallow Copy and Deep Copy

Let’s wrap this article by listing a few major differences between Shallow Copy and Deep Copy of objects in Java:

  1. Shallow copy is a bitwise copy of an object and works fine if the class contains only primitives and immutable fields. But field-by-field assignment will cause references (memory address) to mutable fields/objects being copied. A deep copy will create a distinct copy for each of the object’s mutable fields and referenced objects, rather than references to objects being copied.
  2. The referenced objects are shared in the shallow copy. So if one of either object is modified, the change is visible in the other. On the other hand, new objects are created for any referenced objects in the deep copy. So if one of either object is modified, the change is NOT visible in the other.
  3. Deep copy can be many times slower than the shallow copy. Shallow copy involves copying only from one level of an object, while deep cloning involves recursively copying all mutable types (involve multiple levels) that can have a significant impact on performance.
  4. Shallow copy is preferred if an object consists of only primitive and immutable fields. A deep copy is a preferable approach over a shallow copy when an object has any referenced objects present in it.
  5. Deep copy is tedious to implement, error-prone, and difficult to maintain. The code must be modified every time any change is made to the class fields, unlike a shallow copy implementation.
  6. Default implementation of Object.clone() creates the shallow copy of an object. To create the deep copy of an object, we need to modify mutable fields of the object returned by super.clone() before returning to the caller.

That’s all about shallow copy and deep copy in Java.

 
References:

https://en.wikipedia.org/wiki/Object_copying#Copying_in_Java
https://en.wikipedia.org/wiki/Clone_(Java_method)