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.address
andp2.address
are now completely separate objects.- Modifying
p2.address.city
does 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.