How to Achieve a True Deep Copy in Java?

What is the best way to make a Java deep copy of an object? It’s a bit tricky to implement a proper deep copy function, so how do you ensure that the original object and the cloned one share no references? What steps should be taken to achieve a true deep copy in Java?

1 Like

When you’re trying to make a java deep copy, it can get tricky because a shallow copy doesn’t quite cut it when you’re dealing with nested objects. You really want to ensure that the cloned object is independent of the original, which is why you’ll need to override the clone() method and manually clone each field. Here’s an example:

class Address implements Cloneable {
    String city;
    
    public Address(String city) {
        this.city = city;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return new Address(this.city); // Manually copying field
    }
}

class Person implements Cloneable {
    String name;
    Address address;

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return new Person(this.name, (Address) this.address.clone());
    }
}

:small_blue_diamond: Why this works: You’re manually cloning each object, which ensures that the deep copy is independent of the original. :small_blue_diamond: Downside: You have to implement the clone() method in every class, which can be repetitive and error-prone."

Another solid way to achieve a java deep copy is by using a copy constructor. This approach is often cleaner, especially when you don’t want to mess with Cloneable. Here’s how it works:

class Address {
    String city;
    
    public Address(String city) {
        this.city = city;
    }

    // Copy constructor
    public Address(Address other) {
        this.city = other.city;
    }
}

class Person {
    String name;
    Address address;

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    // Copy constructor
    public Person(Person other) {
        this.name = other.name;
        this.address = new Address(other.address); // Deep copy
    }
}

:small_blue_diamond: Why this works: You don’t need Cloneable, and it’s more flexible. Each field is copied independently. :small_blue_diamond: Downside: It’s a bit repetitive if you have many fields to copy, but it offers great control over the cloning process.

For larger or more complex objects, a java deep copy using serialization can be a game-changer. If your class implements Serializable, you can leverage object streams to copy everything, even nested objects, with minimal code. Here’s an example:

import java.io.*;

class Person implements Serializable {
    String name;
    Address address;

    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    public Person deepCopy() {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            oos.flush();
            
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            
            return (Person) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException("Deep copy failed", e);
        }
    }
}

:small_blue_diamond: Why this works: It handles deep copying all fields automatically, even those nested inside other objects. :small_blue_diamond: Downside: The class and all fields must implement Serializable, which may not always be possible, especially for non-serializable classes.

To make a true deep copy of an object in Java, you can override the clone() method after implementing the Cloneable interface. In the clone() method, ensure that for reference types (like lists or objects), you recursively clone them to avoid shared references. Alternatively, you can use serialization by serializing the object into a byte stream and then deserializing it to create an independent copy. This approach ensures that all nested objects are also cloned, resulting in a true deep copy.

1 Like

Thank you, @jamesalery1, @charity-majors, @Priyadapanicker, and @tim-khorev, for your help! I’ll try the suggested methods and hope to resolve my issues.