Skip to main content

Avoid Overriding clone in Java

High
correctnessmaintainability

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;
}
}