Shallow Copy vs Deep Copy in Java: Key Differences and Usage
shallow copy duplicates an object but shares references to nested objects, while a deep copy duplicates the object and all objects it references recursively. This means changes in nested objects affect shallow copies but not deep copies.Quick Comparison
Here is a quick side-by-side comparison of shallow copy and deep copy in Java.
| Aspect | Shallow Copy | Deep Copy |
|---|---|---|
| Copy Type | Copies top-level object only | Copies object and all nested objects recursively |
| Reference Handling | Nested objects are shared (same references) | Nested objects are duplicated (new references) |
| Modification Effect | Changes in nested objects affect both copies | Changes in nested objects affect only the copied object |
| Implementation | Clone method or copy constructor with default field copy | Custom clone or serialization to copy all nested objects |
| Performance | Faster, less memory | Slower, more memory |
| Use Case | When nested objects are immutable or shared | When full independent copy is needed |
Key Differences
Shallow copy creates a new object and copies the values of the original object's fields to the new object. However, if the field is a reference to another object, only the reference is copied, not the actual nested object. This means both the original and the copy share the same nested objects.
In contrast, deep copy duplicates the original object and recursively copies all objects referenced by it. This results in a completely independent copy where changes to nested objects in one do not affect the other.
Because of this, shallow copy is faster and uses less memory but can cause side effects if nested objects are mutable. Deep copy avoids these side effects but requires more complex code and resources.
Code Comparison
This example shows how to create a shallow copy of an object using the clone() method.
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 } public String toString() { return name + " lives in " + address.city; } } public class ShallowCopyDemo { public static void main(String[] args) throws CloneNotSupportedException { Address addr = new Address("New York"); Person p1 = new Person("Alice", addr); Person p2 = (Person) p1.clone(); p2.name = "Bob"; p2.address.city = "Los Angeles"; // affects p1's address too System.out.println(p1); // Alice lives in Los Angeles System.out.println(p2); // Bob lives in Los Angeles } }
Deep Copy Equivalent
This example shows how to create a deep copy by cloning nested objects manually.
class Address implements Cloneable { String city; Address(String city) { this.city = city; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } 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 { Person cloned = (Person) super.clone(); cloned.address = (Address) address.clone(); // deep copy nested object return cloned; } public String toString() { return name + " lives in " + address.city; } } public class DeepCopyDemo { public static void main(String[] args) throws CloneNotSupportedException { Address addr = new Address("New York"); Person p1 = new Person("Alice", addr); Person p2 = (Person) p1.clone(); p2.name = "Bob"; p2.address.city = "Los Angeles"; // does NOT affect p1's address System.out.println(p1); // Alice lives in New York System.out.println(p2); // Bob lives in Los Angeles } }
When to Use Which
Choose shallow copy when your objects contain immutable nested objects or when sharing nested objects is acceptable and you want better performance. It is simpler and faster but can cause bugs if nested objects are changed unexpectedly.
Choose deep copy when you need a fully independent copy of an object and its nested objects to avoid side effects. This is important when nested objects are mutable and changes should not reflect back to the original.