What is the difference between shallow copy and deep copy in Java?
A shallow copy creates a new object and copies the top-level field values from the original. For primitive fields, this means the value itself is copied. For reference-type fields, only the reference (memory address) is copied — both the original and the copy point to the same nested objects. Modifying a mutable nested object through the copy will therefore affect the original and vice versa.
A deep copy creates a new object and recursively copies all referenced objects as well, producing a completely independent object graph. The copy shares no mutable state with the original. Modifying any nested object in the copy has no effect on the original.
Java's Object.clone() method performs a shallow copy by default when you override it and call super.clone(). To perform a deep copy via clone(), you must override clone() in each referenced class and explicitly clone each reference field.
Practical approaches for deep copying: override clone() with manual deep copy logic; use copy constructors where each class provides a constructor that takes an instance and copies all fields recursively; use serialization (serialize the object to a byte array and deserialize it back — produces a fully disconnected copy, but requires Serializable and is relatively slow); or use a library like Apache Commons Lang's SerializationUtils.clone() or ModelMapper.
Immutable objects change the calculus. String, Integer, and other immutable types are safe to share — a shallow copy of a field pointing to an immutable object is functionally equivalent to a deep copy because neither party can mutate the shared object.
The right choice depends on your use case. Shallow copies are fast and sufficient for read-only scenarios or objects with only primitive/immutable fields. Deep copies are required when you need fully independent state, such as when storing a snapshot of a mutable object or preventing unintended aliasing bugs.
| Aspect | Shallow Copy | Deep Copy |
|---|---|---|
| Nested objects | References shared (same objects) | Recursively duplicated (new objects) |
| Mutation independence | Changes to nested objects affect both copies | Completely independent |
| Performance | Fast — O(n) fields at one level | Slower — proportional to object graph size |
| Default Java behavior | Object.clone() default behavior | Requires explicit implementation |
| Safe when nested objects are | Immutable (String, Integer, etc.) | Mutable and must not be shared |
| Common implementations | super.clone() | Copy constructor, serialization, recursive clone() |
Correctly explains that shallow copy shares nested object references and deep copy recursively duplicates them, and mentions clone() as the default shallow approach.
Adds concrete implementation options (copy constructor, serialization, recursive clone), explains the immutable object exception, and discusses when each is appropriate.
Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.
Get Graded — Free Assessment