C

Core Java tutorial for beginners

Clean • Professional

Java - Deep vs Shallow Copy (Explained with Examples)

5 minute

Deep Copy vs Shallow Copy in Java

In Java, copying objects can be done in two ways — shallow copy and deep copy.

Understanding the difference between them is crucial when working with mutable objects, arrays, or custom classes.

Both techniques create new objects, but they differ in how they handle object references inside objects.


What is a Shallow Copy?

A shallow copy creates a new object, but copies references of nested objects, not their actual values. That means both the original and the copied object share the same referenced objects in memory.

If you modify the inner object in the copy, it will also affect the original.


Example – Shallow Copy

class Address {
    String city;

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

class Student implements Cloneable {
    int id;
    String name;
    Address address;

    Student(int id, String name, Address address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }

    public Object clone() throws CloneNotSupportedException {
        return super.clone(); // shallow copy
    }
}

public class ShallowCopyExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address addr = new Address("Delhi");
        Student s1 = new Student(101, "Aman", addr);
        Student s2 = (Student) s1.clone();

        s2.address.city = "Mumbai"; // change city in cloned object

        System.out.println(s1.address.city); // also changes to Mumbai
    }
}

Output:

Mumbai

Explanation:

Both s1 and s2 share the same Address reference. So, changing the address in s2 affects s1 too.


What is a Deep Copy?

A deep copy creates a new object along with new copies of all referenced objects. That means the original and copied objects are completely independent.

Changes in the cloned object do not affect the original.


Example – Deep Copy

class Address {
    String city;

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

class Student implements Cloneable {
    int id;
    String name;
    Address address;

    Student(int id, String name, Address address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }

    public Object clone() throws CloneNotSupportedException {
        Student s = (Student) super.clone();
        s.address = new Address(address.city); // create new Address object
        return s;
    }
}

public class DeepCopyExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address addr = new Address("Delhi");
        Student s1 = new Student(101, "Aman", addr);
        Student s2 = (Student) s1.clone();

        s2.address.city = "Mumbai";

        System.out.println("Original: " + s1.address.city);
        System.out.println("Clone: " + s2.address.city);
    }
}

Output:

Original: Delhi
Clone: Mumbai

Explanation:

In deep copy, a new Address object is created during cloning, so changes to s2 do not affect s1.


Key Differences Between Shallow and Deep Copy

FeatureShallow CopyDeep Copy
DefinitionCopies only the top-level objectCopies the object and all referenced objects
Nested ObjectsShared between original and cloneNew copies created for nested objects
Memory UsageLess memoryMore memory
PerformanceFasterSlower
IndependenceDependent (changes reflect in both)Independent
Implementationsuper.clone()Custom clone() + new object creation
           ┌──────────────────────────────────┐
           │          Original Object          │
           │  ┌────────────┐                   │
           │  │ Address → A │───┐               │
           └──┴────────────┘   │
                               │
                               ▼
                     ┌────────────────┐
                     │  City = Delhi  │
                     └────────────────┘

          🔸 Shallow Copy
          ┌──────────────────────────────────┐
          │          Copied Object           │
          │  ┌────────────┐                   │
          │  │ Address → A │───────┘           │
          └──┴────────────┘

          🔹 Deep Copy
          ┌──────────────────────────────────┐
          │          Copied Object           │
          │  ┌────────────┐                   │
          │  │ Address → B │───┐               │
          └──┴────────────┘   │
                              ▼
                     ┌────────────────┐
                     │ City = Delhi   │
                     └────────────────┘

Ways to Achieve Deep Copy in Java

learn code with durgesh images

  1. Override clone() properly (as shown above)

  2. Use Copy Constructors

    class Student {
        int id;
        Address address;
        Student(Student s) {
            this.id = s.id;
            this.address = new Address(s.address.city);
        }
    }
    
  3. Serialization (for complex deep copying)

    Serialize and then deserialize the object to get a full deep copy.


Example – Shallow vs Deep Copy Comparison

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

class Employee implements Cloneable {
    String name;
    Address address;

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

    // Shallow copy
    public Employee shallowCopy() throws CloneNotSupportedException {
        return (Employee) super.clone();
    }

    // Deep copy
    public Employee deepCopy() throws CloneNotSupportedException {
        Employee copy = (Employee) super.clone();
        copy.address = new Address(address.city);
        return copy;
    }
}

public class CopyTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Employee e1 = new Employee("Ravi", new Address("Delhi"));
        Employee e2 = e1.shallowCopy();
        Employee e3 = e1.deepCopy();

        e2.address.city = "Mumbai";
        e3.address.city = "Chennai";

        System.out.println("Original: " + e1.address.city);
        System.out.println("Shallow Copy: " + e2.address.city);
        System.out.println("Deep Copy: " + e3.address.city);
    }
}

Output:

Original: Mumbai
Shallow Copy: Mumbai
Deep Copy: Chennai

When to Use

Use CaseRecommended Copy
Simple objects without referencesShallow Copy
Complex/nested objectsDeep Copy
Large data (performance priority)Shallow Copy
Critical data isolation (safety)Deep Copy

Points to Remember

  • clone() method in Object performs shallow copy by default.
  • To perform deep copy, manually clone referenced objects inside clone().
  • Always implement Cloneable interface when overriding clone().
  • Alternatively, use copy constructors or serialization for cleaner deep copying.

Article 0 of 0