Introduction
Copying objects in Java is not as simple as assigning variables. Understanding shallow vs deep copy ensures that your objects behave correctly when duplicated.
Why It Matters
- Prevents unintended data sharing between objects.
- Avoids bugs when working with mutable objects.
- Ensures proper object design in real-world projects.
When to Use
- Shallow Copy: When you want a quick, low-cost duplicate and inner objects are immutable or don’t need separation.
- Deep Copy: When you need a full independent copy, especially with mutable or nested objects.
Core Concepts
What is Shallow Copy?
- Copies the top-level object only.
- References of nested objects are shared, not cloned.
- Typically implemented via
clone()
or copy constructors.
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
}
}
What is Deep Copy?
- Creates a new copy of all nested objects.
- Ensures full independence of the clone.
@Override
protected Object clone() throws CloneNotSupportedException {
Person cloned = (Person) super.clone();
cloned.address = new Address(this.address.city); // Deep copy of nested object
return cloned;
}
Real-World Analogy
- Shallow Copy: Photocopying a folder but leaving all internal files as links to originals.
- Deep Copy: Creating a new folder and duplicating every file inside.
Comparison Table
Feature | Shallow Copy | Deep Copy |
---|---|---|
Speed | Faster | Slower |
Memory Usage | Less | More |
Nested Objects | Shared references | Fully cloned |
Use Case | Immutable or simple objects | Mutable, complex object graphs |
Implementation | clone() , copy constructor |
Manual clone, serialization, custom logic |
Real-World Use Cases
- Shallow Copy:
- DTOs with immutable fields.
- Lightweight duplication in caching.
- Deep Copy:
- Cloning configuration objects.
- Game state snapshots.
- Complex data structures.
Common Mistakes & Anti-Patterns
- Assuming
clone()
does deep copy by default:- Default implementation is always shallow.
- Copying mutable objects shallowly:
- Leads to shared state bugs.
- Ignoring
CloneNotSupportedException
:- All classes must implement
Cloneable
to useclone()
.
- All classes must implement
Performance & Memory Implications
- Shallow Copy:
- Low overhead, fast.
- Can cause hidden side effects if nested objects are modified.
- Deep Copy:
- Expensive in CPU and memory.
- Useful for data isolation and thread safety.
Tuning Tips
- Use deep copy only when necessary.
- Consider immutability to avoid deep copy overhead.
Best Practices
- Favor copy constructors or factory methods over
clone()
. - Use libraries like Apache Commons
SerializationUtils.clone()
for deep copy. - Keep objects immutable to avoid needing deep copies.
- Clearly document copy behavior.
Java Version Relevance
Version | Change |
---|---|
Java 8 | No direct changes, serialization-based cloning common |
Java 9+ | clone() discouraged in favor of copy methods |
Java 14+ | Records introduced (immutability reduces need for deep copy) |
Code Example: Testing Shallow vs Deep Copy
public class CopyDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address("New York");
Person p1 = new Person("John", address);
Person p2 = (Person) p1.clone(); // Shallow or deep depending on implementation
p2.address.city = "Los Angeles";
System.out.println(p1.address.city); // Shallow: Los Angeles, Deep: New York
}
}
Conclusion & Key Takeaways
- Shallow copies share nested object references, deep copies don’t.
- Choose based on object mutability and performance needs.
- Avoid default
clone()
; prefer copy constructors or immutability. - Deep copies ensure safety but cost performance.
FAQ
-
Does
Object.clone()
perform a deep copy?
No, it performs a shallow copy. -
When should I use deep copy?
When nested objects are mutable and need full separation. -
Is serialization a way to deep copy?
Yes, but slower compared to manual copy. -
What’s better:
clone()
or copy constructor?
Copy constructors are safer and more flexible. -
Do immutable objects need deep copy?
No, because they can’t change. -
What if my class has many nested objects?
Implement custom deep copy logic or use libraries. -
Is deep copy thread-safe?
It helps avoid shared state, improving thread safety. -
What’s the cost of deep copy?
Higher CPU and memory usage. -
Can
final
fields be deep copied?
Yes, if initialized with new objects in constructor. -
Does Java provide built-in deep copy?
No, you must implement it manually or use third-party utilities.