0
0
JavaComparisonBeginner · 4 min read

Shallow Copy vs Deep Copy in Java: Key Differences and Usage

In Java, a shallow copy duplicates an object but shares references to nested objects, while a deep copy duplicates the object and all objects it references recursively. This means changes in nested objects affect shallow copies but not deep copies.
⚖️

Quick Comparison

Here is a quick side-by-side comparison of shallow copy and deep copy in Java.

AspectShallow CopyDeep Copy
Copy TypeCopies top-level object onlyCopies object and all nested objects recursively
Reference HandlingNested objects are shared (same references)Nested objects are duplicated (new references)
Modification EffectChanges in nested objects affect both copiesChanges in nested objects affect only the copied object
ImplementationClone method or copy constructor with default field copyCustom clone or serialization to copy all nested objects
PerformanceFaster, less memorySlower, more memory
Use CaseWhen nested objects are immutable or sharedWhen full independent copy is needed
⚖️

Key Differences

Shallow copy creates a new object and copies the values of the original object's fields to the new object. However, if the field is a reference to another object, only the reference is copied, not the actual nested object. This means both the original and the copy share the same nested objects.

In contrast, deep copy duplicates the original object and recursively copies all objects referenced by it. This results in a completely independent copy where changes to nested objects in one do not affect the other.

Because of this, shallow copy is faster and uses less memory but can cause side effects if nested objects are mutable. Deep copy avoids these side effects but requires more complex code and resources.

⚖️

Code Comparison

This example shows how to create a shallow copy of an object using the clone() method.

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

class Person implements Cloneable {
    String name;
    Address address;

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); // shallow copy
    }

    public String toString() {
        return name + " lives in " + address.city;
    }
}

public class ShallowCopyDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address addr = new Address("New York");
        Person p1 = new Person("Alice", addr);
        Person p2 = (Person) p1.clone();

        p2.name = "Bob";
        p2.address.city = "Los Angeles"; // affects p1's address too

        System.out.println(p1); // Alice lives in Los Angeles
        System.out.println(p2); // Bob lives in Los Angeles
    }
}
Output
Alice lives in Los Angeles Bob lives in Los Angeles
↔️

Deep Copy Equivalent

This example shows how to create a deep copy by cloning nested objects manually.

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Person implements Cloneable {
    String name;
    Address address;

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person cloned = (Person) super.clone();
        cloned.address = (Address) address.clone(); // deep copy nested object
        return cloned;
    }

    public String toString() {
        return name + " lives in " + address.city;
    }
}

public class DeepCopyDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address addr = new Address("New York");
        Person p1 = new Person("Alice", addr);
        Person p2 = (Person) p1.clone();

        p2.name = "Bob";
        p2.address.city = "Los Angeles"; // does NOT affect p1's address

        System.out.println(p1); // Alice lives in New York
        System.out.println(p2); // Bob lives in Los Angeles
    }
}
Output
Alice lives in New York Bob lives in Los Angeles
🎯

When to Use Which

Choose shallow copy when your objects contain immutable nested objects or when sharing nested objects is acceptable and you want better performance. It is simpler and faster but can cause bugs if nested objects are changed unexpectedly.

Choose deep copy when you need a fully independent copy of an object and its nested objects to avoid side effects. This is important when nested objects are mutable and changes should not reflect back to the original.

Key Takeaways

Shallow copy duplicates only the top-level object, sharing nested object references.
Deep copy duplicates the entire object graph, creating independent nested objects.
Use shallow copy for better performance when nested objects are immutable or shared.
Use deep copy to avoid side effects when nested objects are mutable and independent copies are needed.
Deep copy requires more complex code, often cloning nested objects manually.