Let’s break down the difference between shallow copy and deep copy in Java — this is a classic interview topic, especially for cloning objects.
🌐 What is a Shallow Copy?
A shallow copy copies only the top-level structure of an object.
- It copies references to nested objects instead of copying the nested objects themselves.
- Both the original and the copied object share the same nested (inner) objects.
Example — Shallow Copy
class Address {
String city;
public Address(String city) {
this.city = city;
}
}
class Person implements Cloneable {
String name;
Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
@Override
protected Person clone() throws CloneNotSupportedException {
return (Person) super.clone(); // Shallow copy
}
}
Usage
Person p1 = new Person("Alice", new Address("New York"));
Person p2 = p1.clone();
p2.name = "Bob";
p2.address.city = "Los Angeles"; // Changes reflected in both!
System.out.println(p1.address.city); // "Los Angeles" — both share same address
🔎 Summary of Shallow Copy
Property | Explanation |
---|---|
Top-level fields (primitives) | Copied directly |
Reference fields (objects) | References are copied (both objects share the same inner objects) |
Speed | Faster (no need to copy everything deeply) |
When to use | Objects where sharing inner objects is fine (e.g., cache) |
🌊 What is a Deep Copy?
A deep copy copies the top-level object and all nested objects recursively.
- The original and copy are completely independent.
- Changes to inner objects in the copy do not affect the original.
Example — Deep Copy
class Address {
String city;
public Address(String city) {
this.city = city;
}
public Address(Address other) {
this.city = other.city; // Copy inner field
}
}
class Person implements Cloneable {
String name;
Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
@Override
protected Person clone() {
return new Person(this.name, new Address(this.address)); // Deep copy
}
}
Usage
Person p1 = new Person("Alice", new Address("New York"));
Person p2 = p1.clone();
p2.name = "Bob";
p2.address.city = "Los Angeles"; // Changes to p2 do NOT affect p1
System.out.println(p1.address.city); // "New York"
📊 Summary of Deep Copy
Property | Explanation |
---|---|
Top-level fields (primitives) | Copied directly |
Reference fields (objects) | New copies are created (full copy) |
Speed | Slower (copies everything) |
When to use | For truly independent copies (e.g., working on data snapshots) |
🔥 Key Differences Summary Table
Feature | Shallow Copy | Deep Copy |
---|---|---|
Copies top-level fields? | ✅ Yes | ✅ Yes |
Copies nested objects? | ❌ No (shared) | ✅ Yes (new objects) |
Performance | 🚀 Fast | 🐢 Slower |
Independence | ❌ Linked (modifying inner objects affects both) | ✅ Fully independent |
Typical Use Case | When nested objects are immutable | When nested objects are mutable and need full separation |
⚠️ Important Note — Object.clone()
- By default,
clone()
in Java does shallow copying. - If you want deep copying, you have to override
clone()
and explicitly copy inner objects.
📣 Quick Interview Pro Tip
✅ When asked, say:
“Shallow copy only copies the outer object — inner objects are shared. Deep copy copies everything, including deep nested objects, creating a completely independent object graph.”
✅ Mention:
clone()
does shallow copy by default.- To make a deep copy, you have to manually copy all nested objects.
💡 Bonus Trick
If the object is Serializable, you can do deep copy using serialization like this:
// Deep copy via serialization (useful for large objects with many fields)
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(original);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
Object copy = ois.readObject(); // Fully independent deep copy