Understanding Shallow, Lazy and Deep Clone in Java
When you want to create copies of objects for various purposes in Java, there are three common approaches that can be used for object copying: shallow cloning, deep cloning, and lazy cloning. In this article, we will explore the concepts of shallow copy and deep copy in Java, their differences, and when to use each of them. Moreover, we will mention lazy copy and try to give examples of it.
If you don’t have a medium membership, you can use this link to reach the article without a paywall.
2. Explaining the Concepts
2.1. What is the Shallow Clone?
A shallow clone of an object in Java creates a new object but does not duplicate its nested objects. Instead, it copies references to the nested objects. In other words, a shallow clone creates a new instance of the outer object, but the inner objects are shared between the original and the cloned object. Changes made to the inner objects in the clone will affect the original, and vice versa.
2.2. What is the Lazy Clone?
Lazy cloning is a variation of shallow cloning, where the actual copying of nested objects is delayed until a change is made to the clone. Initially, a lazy clone creates a new instance of the outer object, similar to shallow cloning. However, it does not copy the nested objects immediately. Instead, it creates new instances of nested objects only when a modification is attempted on the cloned object. This way, memory and processing resources are conserved until they are actually needed.
2.3. What is the Deep Clone?
In contrast, a deep clone creates an entirely independent copy of the original object, including all nested objects. This means that any changes made to the cloned object or its nested objects will not affect the original object, and vice versa. Deep cloning ensures that the cloned object is a true replica, with no shared references to other objects.
3. Differences
Let’s elaborate on the differences between shallow and deep cloning:
3.1. Shallow Clone
- Shallow cloning is faster and requires less memory compared to deep cloning because it does not create copies of nested objects.
- Changes made to nested objects within the cloned object affect the original object since they share references.
- Shallow cloning is suitable when you want to create a new object with the same references to inner objects for scenarios where sharing is acceptable.
3.2. Deep Clone
- Deep cloning creates true, independent copies of both the outer and inner objects, ensuring that changes in one do not affect the other.
- Deep cloning consumes more memory and is slower compared to shallow cloning, especially for complex object structures.
- Deep cloning is necessary when you need to create a completely separate and isolated copy of an object, such as when dealing with sensitive data or modifying the clone independently of the original.
3.3. Lazy Clone
- Lazy cloning is a compromise between shallow and deep cloning, saving memory and processing until changes are actually required.
- Initially, a lazy clone behaves like a shallow clone but creates new instances of nested objects only when modifications are attempted.
- Lazy cloning is suitable when you want to optimize memory usage and don’t expect to modify most of the nested objects in the cloned structure.
To illustrate the difference between shallow and deep cloning, let’s consider an example using Java’s Cloneable interface and the clone() method:
import java.util.ArrayList;
import java.util.List;
class Person implements Cloneable {
private String name;
private List<String> phoneNumbers;
public Person(String name, List<String> phoneNumbers) {
this.name = name;
this.phoneNumbers = phoneNumbers;
}
public List<String> getPhoneNumbers() {
return phoneNumbers;
}
public String getName() {
return name;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class CloneExample {
public static void main(String[] args) throws CloneNotSupportedException {
List<String> originalPhoneNumbers = new ArrayList<>();
originalPhoneNumbers.add("123-456-7890");
Person originalPerson = new Person("John", originalPhoneNumbers);
// Shallow clone
Person shallowClone = (Person) originalPerson.clone();
// Deep clone using custom method (explained below)
Person deepClone = deepClone(originalPerson);
// Modify the shallow clone
shallowClone.getPhoneNumbers().add("987-654-3210");
// Modify the deep clone
deepClone.getPhoneNumbers().add("555-555-5555");
System.out.println("Original Person: " + originalPerson.getPhoneNumbers());
System.out.println("Shallow Clone: " + shallowClone.getPhoneNumbers());
System.out.println("Deep Clone: " + deepClone.getPhoneNumbers());
}
public static Person deepClone(Person original) throws CloneNotSupportedException {
List<String> phoneNumbersCopy = new ArrayList<>(original.getPhoneNumbers());
return new Person(original.getName(), phoneNumbersCopy);
}
}In this example, we create a Person class with a name and a list of phone numbers. We then create an original person object and make both a shallow and a deep clone of it. We modify the clones' phone numbers and observe the impact on the original person. Output of the code is:
Original Person: [123-456-7890, 987-654-3210]
Shallow Clone: [123-456-7890, 987-654-3210]
Deep Clone: [123-456-7890, 555-555-5555]So when we changed the object that is copied with shallow copy, effects can be seen on the original object. But when object that is deep cloned is changed, the original object remains unaffected.
4. Different Ways to Deep Copy Objects
4.1 Copy Method
The first way to deep copy objects is creating a copy method as we did in the above example. This method handles all object creations including the nested ones also.
public static Person deepClone(Person original) {
List<String> phoneNumbersCopy = new ArrayList<>(original.getPhoneNumbers());
return new Person(original.getName(), phoneNumbersCopy);
}4.2 Copy Constructor
Second way, my favourite one, is to create a constructor that takes object itself as a parameter and returns a deep copy of the object. In that way, all the copy operation can be handled in the constructor method and provide a clean usage for developers.
public Person(Person that) {
this(that.getName(), new ArrayList<>(that.getPhoneNumbers()));
}4.3 Serialization
Deep copies of objects can be created by serializing and deserializing the original object. But this requires a bit of caution because all the nested objects should be serializable too. If any of the nested objects are not serializable, the copy object and the original object will not be the same. External libraries can be used for serialization such as GSON, Jackson, and ApacheCommons. But in this example, we will use input and output streams.
public static <T> T cloneUsingSerialization(T original) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(original);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (T) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
return null;
}
}In Java, shallow cloning and deep cloning serve different purposes depending on your specific requirements. Shallow cloning is suitable when you want to create a new object with shared references to nested objects, while deep cloning is necessary when you need a fully independent copy of an object with all its nested objects. Understanding these concepts and their differences is crucial for effective object manipulation and data integrity in your Java applications.
👏 Thank You for Reading!
👨💼 I appreciate your time and hope you found this story insightful. If you enjoyed it, don’t forget to show your appreciation by clapping 👏 for the hard work!
📰 Keep the Knowledge Flowing by Sharing the Article!
✍ Feel free to share your feedback or opinions about the story. Your input helps me improve and create more valuable content for you.
✌ Stay Connected! 🚀 For more engaging articles, make sure to follow me on social media:
🔍 Explore More! 📖 Dive into a treasure trove of knowledge at Codimis. There’s always more to learn, and we’re here to help you on your journey of discovery.






