advanced.java
← All concepts
Object methods · ch. 2, p. 14

clone, copying and defensive copies

Object.clone() produces a shallow copy through a broken protocol. A copy constructor or static factory is clearer, and mutable fields crossing an API boundary need copying in both directions.

Cloneable is a marker interface that does not declare clone(), and Object.clone() is protected and throws unless the marker is present. The result is a shallow copy: nested mutable objects stay shared.

// Prefer this
public Period(Period other) {
    this.start = new Date(other.start.getTime());
    this.end   = new Date(other.end.getTime());
}

Defensive copying, in and out

A constructor that stores a caller’s mutable argument by reference has handed that caller a way to mutate the object afterwards. A getter that returns the internal reference does the same in the other direction.

public final class Period {
    private final Date start;

    public Period(Date start) {
        this.start = new Date(start.getTime());   // copy in
    }

    public Date getStart() {
        return new Date(start.getTime());          // copy out
    }
}

Copy in before validating, or a hostile caller can mutate the value between the check and the store.

The whole problem disappears with java.timeInstant and LocalDate are immutable, so no copying is needed.

2 questions on this concept Drill it