The best cloning method depends on your use case. Below is a comparison of three common cloning methods:
- Shallow Copy using
super.clone()
(Default Cloning) - Deep Copy using
super.clone()
+ Manual Cloning - Copy Constructor (Alternative Approach)
1. Shallow Copy (super.clone()
)
🚀 Best for:
- Simple objects (no references to other objects).
- When modifying cloned object should affect the original.
✅ Advantages:
- Fast and memory-efficient.
- Easy to implement.
- Works well for immutable objects (like
String
).
❌ Disadvantages:
- If an object contains mutable fields (e.g., arrays, lists, or other objects), changes in the clone will affect the original.
Example of Shallow Copy:
class Person implements Cloneable {
String name;
Person(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // Performs shallow copy
}
}
public class ShallowCloneExample {
public static void main(String[] args) throws CloneNotSupportedException {
Person p1 = new Person("Alice");
Person p2 = (Person) p1.clone(); // Cloning
System.out.println(p1.name); // Alice
System.out.println(p2.name); // Alice
}
}
✅ Works great for simple objects with primitive fields.
🚨 Problem arises when cloning objects with references.
2. Deep Copy (super.clone()
+ Manual Cloning)
🚀 Best for:
- Objects containing mutable fields (e.g., Lists, custom objects).
- When cloned objects must be fully independent.
✅ Advantages:
- Ensures that modifications in the clone do not affect the original.
- Works well for complex objects.
❌ Disadvantages:
- Slightly slower than shallow copy (creates new copies of all objects).
- Requires manual cloning of each reference field.
Example of Deep Copy:
class Address implements Cloneable {
String city;
Address(String city) {
this.city = city;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return new Address(this.city); // Manually creating a copy
}
}
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(); // Deep Cloning
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!)
}
}
✅ Best for ensuring cloned objects are fully independent.
🚀 Slower than shallow copy, but avoids unintended side effects.
3. Copy Constructor (Alternative to Cloning)
🚀 Best for:
- When
Cloneable
is not preferred. - Avoiding issues related to
clone()
andCloneable
.
✅ Advantages:
- Does not require
Cloneable
. - Works naturally with deep copying.
- Easier to customize than
clone()
.
❌ Disadvantages:
- Requires extra constructor logic.
- Not a built-in cloning mechanism.
Example of Copy Constructor:
class Address {
String city;
Address(String city) {
this.city = city;
}
// Copy constructor
Address(Address other) {
this.city = other.city;
}
}
class Person {
String name;
Address address;
Person(String name, String city) {
this.name = name;
this.address = new Address(city);
}
// Copy constructor for deep copy
Person(Person other) {
this.name = other.name;
this.address = new Address(other.address); // Deep Copy
}
}
public class CopyConstructorExample {
public static void main(String[] args) {
Person p1 = new Person("Alice", "New York");
Person p2 = new Person(p1); // Cloning using copy constructor
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!)
}
}
✅ Works well for deep copying without using Cloneable
.
🚀 Preferred when working with immutable objects.
Comparison of Cloning Methods
Feature | Shallow Copy (super.clone() ) | Deep Copy (super.clone() + Manual Cloning) | Copy Constructor |
---|---|---|---|
Requires Cloneable ? | ✅ Yes | ✅ Yes | ❌ No |
Copies References? | ✅ Yes (Same objects are shared) | ❌ No (Creates new copies) | ❌ No (Creates new copies) |
Performance | ⚡ Fastest | 🐢 Slightly slower | 🐢 Slightly slower |
Best for | Simple objects | Objects with references | Immutable objects |
Common Use Case | Cloning objects with only primitive fields | Cloning complex objects with references | Alternative to cloning |
Which Cloning Method is Preferable?
Scenario | Preferred Cloning Method |
---|---|
Cloning simple objects | ✅ Shallow Copy (super.clone() ) |
Cloning complex objects with references | ✅ Deep Copy (super.clone() + Manual Cloning) |
Cloning without Cloneable | ✅ Copy Constructor |
Cloning large objects frequently | ✅ Shallow Copy (for performance) |
Cloning objects used in collections (List , Map ) | ✅ Deep Copy or Copy Constructor |
🚀 Best Overall Choice:
- Use Deep Copy (
super.clone()
+ Manual Cloning) for complex objects. - Use Copy Constructor if you don’t want to use
Cloneable
.