Avoid Overriding clone
in Java
What is it?
This practice addresses the issue of overriding the Object.clone
method in Java. Instead of using Object.clone
, consider using copy constructors, factory methods, or custom copy functions.
Why apply it?
The Object.clone
mechanism is flawed due to its marker interface nature, bypassing constructors in object creation, and its inherent design issues like handling type casts and exceptions. Better alternatives exist that are more robust and clearer.
How to fix it?
Avoid implementing java.lang.Cloneable
and overriding Object.clone
. Use copy constructors, factory methods, or well-defined copy functions to replicate objects safely and predictably.
Examples
Example 1:
Negative
Inappropriately overrides clone
, bypasses constructor calls, and casts objects unsafely.
class Entity implements Cloneable { // Noncompliant
public int value;
public List<Entity> children;
Entity() {
EntityManager.register(this);
}
@Override
public Entity clone() {
try {
Entity copy = (Entity) super.clone(); // Unsafe casting and bypassing constructor
copy.children = children.stream().map(Entity::clone).toList();
return copy;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
Example 2:
Positive
Uses a copy constructor to create a new instance while preserving invariants and ensuring type safety.
class Entity { // Compliant
public int value;
public List<Entity> children;
// Initializing constructor
Entity() {
EntityManager.register(this);
}
// Copy constructor
Entity(Entity template) {
this.value = template.value;
this.children = template.children.stream().map(Entity::new).toList();
}
}
Negative
Uses the Cloneable
interface and overrides the clone
method, leading to flawed object duplication.
class Entity implements Cloneable { // Noncompliant
public int value;
public List<Entity> children;
Entity() {
EntityManager.register(this);
}
@Override
public Entity clone() {
try {
Entity copy = (Entity) super.clone(); // Skips required initializations
copy.children = new ArrayList<>(children); // Shallow copy issue
return copy;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
Example 3:
Positive
Uses a factory method to clearly and safely create a new instance from a template.
class Entity { // Compliant
public int value;
public List<Entity> children;
Entity() {
EntityManager.register(this);
}
public static Entity create(Entity template) {
Entity entity = new Entity();
entity.value = template.value;
entity.children = template.children.stream().map(Entity::new).toList();
return entity;
}
}