avatarUğur Taş

Summary

The provided web content discusses the concepts of shallow, lazy, and deep cloning in Java, explaining their differences and use cases, along with examples and methods for implementing deep copies.

Abstract

Understanding the nuances of object cloning is crucial in Java for managing object copies effectively. The article delves into three main cloning strategies: shallow cloning, which copies an object but shares references to nested objects; lazy cloning, which postpones the copying of nested objects until modifications are made; and deep cloning, which creates a fully independent copy of an object, including all nested objects. The author illustrates these concepts with a Java example using the Cloneable interface and the clone() method, demonstrating the impact of changes to the original object in shallow versus deep cloning. Additionally, the article presents different approaches to achieve deep copying, such as copy methods, copy constructors, and serialization techniques, emphasizing the importance of choosing the right cloning method based on the application's requirements to ensure data integrity and efficient memory usage.

Opinions

  • The author suggests that shallow cloning is suitable for scenarios where sharing references to nested objects is acceptable and where memory efficiency is a priority.
  • Lazy cloning is presented as an optimization technique, particularly useful when modifications to the cloned object are infrequent, thus saving memory and processing power.
  • Deep cloning is deemed necessary for creating completely isolated copies of objects, which is important when dealing with sensitive data or when the clone needs to be modified independently without affecting the original object.
  • The author expresses a preference for the copy constructor method as a clean and straightforward approach to deep copying.
  • The use of serialization for deep copying is acknowledged as a powerful method, but it comes with a caution about ensuring that all nested objects are serializable.
  • The article encourages readers to apply these cloning strategies thoughtfully, considering the specific needs of their Java applications for maintaining data integrity and optimizing performance.

Understanding Shallow, Lazy and Deep Clone in Java

Photo by Михаил Секацкий on Unsplash

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.

Java
Deep Copy
Shallow Copy
Objectcloning
Deep Clone
Recommended from ReadMedium