Shallow Copy vs Deep Copy
Shallow copy vs deep copy explained — reference aliasing, Object.clone() behavior and when to deep copy — with a Java example and interview Q&A.
Expected Interview Answer
A shallow copy duplicates an object’s top-level fields but keeps any reference-type fields pointing to the same underlying objects as the original, while a deep copy recursively duplicates every referenced object so the copy shares no mutable state with the source.
With a shallow copy, primitive fields are duplicated by value, but object references (arrays, lists, nested objects) are duplicated by reference — both the original and the copy end up pointing at the same inner object, so mutating it through one is visible through the other. A deep copy walks the full object graph and creates independent copies of every referenced object, so the two structures become fully isolated. Shallow copies are cheap and fine when nested state is immutable or intentionally shared; deep copies cost more time and memory but are required when the copy must be safely mutated without side effects on the original. Java’s default Object.clone() performs a shallow copy unless the class explicitly overrides it to deep-copy mutable fields.
- Shallow copy: fast, low memory, fine for immutable or shared nested state
- Deep copy: full isolation, safe independent mutation
- Choosing correctly avoids subtle aliasing bugs
- Clarifies exactly what “copying an object” means in a given API
AI Mentor Explanation
Photocopying a team roster sheet is a shallow copy — the names are duplicated, but if the sheet had a sticky note listing “injured players” attached, both copies point to that same physical note, so scratching a name off one note changes what the other sheet shows too. A deep copy would mean writing a brand-new injured-players note from scratch for the second sheet, fully separate from the first. Only the deep version lets you edit one team’s injury list without silently altering the other.
Step-by-Step Explanation
Step 1
Copy top-level primitive fields
Both shallow and deep copies duplicate primitive values (int, boolean, etc.) independently by value.
Step 2
Shallow: reuse reference fields
A shallow copy assigns the same object reference for arrays/objects, so both copies alias the same nested data.
Step 3
Deep: recursively clone references
A deep copy creates new instances of every referenced object, walking the full object graph.
Step 4
Verify isolation
Mutate a nested field through one copy and confirm whether the other copy is affected — that test distinguishes shallow from deep.
What Interviewer Expects
- A precise definition of both, contrasted directly
- Explanation of aliasing and why mutation through one copy can leak into the other
- Knowledge that Object.clone() is shallow by default in Java
- Awareness of the performance/isolation tradeoff between the two
Common Mistakes
- Saying a shallow copy duplicates “nothing” — it does copy primitive fields and top-level structure
- Assuming Java’s default clone() is deep
- Forgetting immutable nested fields make shallow copies effectively safe
- Not mentioning the performance cost of deep copying large object graphs
Best Answer (HR Friendly)
“A shallow copy makes a new object but its inner objects are still shared with the original, so changing something nested affects both. A deep copy fully duplicates everything inside, so the two copies are completely independent of each other. I pick shallow when nested data won’t change, and deep when I need true isolation.”
Code Example
class Player {
String name;
Player(String name) { this.name = name; }
}
class Team implements Cloneable {
List<Player> players;
Team(List<Player> players) { this.players = players; }
// Shallow copy: default clone() reuses the same players list
Team shallowCopy() {
return new Team(this.players);
}
// Deep copy: build a brand new list and new Player instances
Team deepCopy() {
List<Player> copied = new ArrayList<>();
for (Player p : players) copied.add(new Player(p.name));
return new Team(copied);
}
}
Team original = new Team(new ArrayList<>(List.of(new Player("Rex"))));
Team shallow = original.shallowCopy();
Team deep = original.deepCopy();
shallow.players.get(0).name = "Changed";
// original.players.get(0).name is also "Changed" (shared reference)
// deep.players.get(0).name is still "Rex" (fully isolated)Follow-up Questions
- Does Java’s default Object.clone() produce a shallow or deep copy?
- How would you implement a deep copy for a class with nested mutable objects?
- What bugs can arise from unintentionally sharing state via a shallow copy?
- Is serialization-based cloning shallow or deep, and what are its drawbacks?
MCQ Practice
1. In a shallow copy, reference-type fields are?
A shallow copy assigns the same object reference, so both copies alias the same nested object.
2. A deep copy guarantees that?
A deep copy recursively duplicates referenced objects, producing full isolation from the source.
3. Java’s default Object.clone() behavior is?
Object.clone() performs a shallow, field-by-field copy by default; deep copying must be coded manually.
Flash Cards
Shallow copy in one line? — Copies top-level fields; reference fields still point to the same shared objects.
Deep copy in one line? — Recursively duplicates every referenced object for full isolation.
Java default clone() is? — Shallow, unless the class overrides it to deep-copy mutable fields.
When is shallow copy safe? — When nested fields are immutable or intentionally shared.