2. Shallow Copy Issue (Mutable Fields)
Shallow copying fails when an object contains references to other objects.
Example: Issue with Shallow Copy
class Address {
String city;
Address(String city) {
this.city = city;
}
}
class Person implements Cloneable {
String name;
Address address; // Reference to another object
Person(String name, String city) {
this.name = name;
this.address = new Address(city);
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // Shallow copy (copies reference)
}
}
public class ShallowCopyIssue {
public static void main(String[] args) throws CloneNotSupportedException {
Person p1 = new Person("Alice", "New York");
Person p2 = (Person) p1.clone();
System.out.println(p1.address.city); // New York
System.out.println(p2.address.city); // New York
p2.address.city = "Los Angeles"; // Modifying p2's address
System.out.println(p1.address.city); // Los Angeles (original modified!)
}
}
🚨 Issue: Changing p2.address.city also changes p1.address.city because both objects share the same address reference.
✅ Solution: Use Deep Copy.
3. Deep Copy (Fixing the Reference Issue)
A deep copy creates a completely independent object, including copies of all referenced objects.
Example: Deep Copy Implementation
class Address implements Cloneable {
String city;
Address(String city) {
this.city = city;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return new Address(this.city); // Manually clone the Address object
}
}
class Person implements Cloneable {
String name;
Address address;
Person(String name, String city) {
this.name = name;
this.address = new Address(city);
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person clonedPerson = (Person) super.clone(); // Shallow copy
clonedPerson.address = (Address) address.clone(); // Deep copy of Address
return clonedPerson;
}
}
public class DeepCloneExample {
public static void main(String[] args) throws CloneNotSupportedException {
Person p1 = new Person("Alice", "New York");
Person p2 = (Person) p1.clone();
System.out.println(p1.address.city); // New York
System.out.println(p2.address.city); // New York
p2.address.city = "Los Angeles"; // Change p2's address
System.out.println(p1.address.city); // New York (original unchanged!)
}
}
✅ Deep Copy Fixes the Issue!
p1.addressandp2.addressare now completely separate objects.- Modifying
p2.address.citydoes not affectp1.address.city.
4. Copy Constructor (Alternative to clone())
Instead of using clone(), you can manually create a copy constructor.
Example: Copy Constructor
class Person {
String name;
Person(String name) {
this.name = name;
}
// Copy constructor
Person(Person other) {
this.name = other.name;
}
}
public class CopyConstructorExample {
public static void main(String[] args) {
Person p1 = new Person("Alice");
Person p2 = new Person(p1); // Copy constructor
System.out.println(p1.name); // Alice
System.out.println(p2.name); // Alice
}
}
✅ Advantage of Copy Constructor:
- No need to implement
Cloneable. - Works well for deep copies.
Comparison of Shallow Copy vs. Deep Copy
| Feature | Shallow Copy | Deep Copy |
|---|---|---|
| Copy Type | Copies object references | Copies object content |
| Speed | ✅ Faster | ❌ Slower |
| Reference Fields | ❌ Shared | ✅ Cloned |
| Use Case | When object references should be shared | When object references must be independent |
5. Summary of Object Cloning
| Concept | Description |
|---|---|
Cloneable Interface | Required for using clone(). |
Shallow Copy (super.clone()) | Copies references instead of actual objects. |
| Deep Copy (Manually Clone Fields) | Ensures each field is independently copied. |
| Copy Constructor Alternative | More flexible, avoids Cloneable. |
🚀 Best Practice:
- Use shallow copy if references should be shared.
- Use deep copy if references must be independent.