Why does Effective Java discourage clone()/Cloneable, and what should you use instead?
answer
- Cloneable = broken marker (mutates Object.clone)
- Shallow default + checked exception + constructor bypass
- Clashes with final fields / immutability
- Prefer copy constructor / copy factory
- clone() still right for arrays
basics
~20 sclone() has many flaws: Cloneable is a marker interface that magically changes Object.clone(), the default copy is shallow, it throws a checked exception, and it skips constructors so it clashes with final fields. Effective Java recommends a copy constructor or copy factory instead.
solid answer
~50 sEffective Java (Item 13) calls the Cloneable mechanism deeply flawed. Cloneable is a marker interface with no methods that nonetheless alters the behavior of the protected Object.clone(); clone()'s default copy is shallow, so mutable fields are silently shared; clone() throws a checked CloneNotSupportedException for no real benefit; and because clone() bypasses constructors, it cannot deep-copy into final fields and skips invariant checks, making it hard to combine with immutability. It is also fragile across inheritance and tricky to implement correctly (super.clone(), covariant return, deep-copy each mutable field). The recommended alternative is a copy constructor (Foo(Foo other)) or a static copy factory (Foo.copyOf(other)): both run real construction so they validate, can deep-copy into final fields, keep the class immutable, throw no checked exception, and can even accept an interface type for conversion. Reserve clone() for places the platform forces it — chiefly arrays, where array.clone() is the idiomatic copy.
code
java · 20 lines// Preferred: copy constructor (+ optional copy factory) instead of Cloneable
final class Account {
private final String owner;
private final List<Transaction> history;
Account(String owner, List<Transaction> history) {
this.owner = owner;
this.history = List.copyOf(history); // validates + defensive deep-ish copy
}
// copy constructor: real construction, fields stay final, no Cloneable
Account(Account other) {
this(other.owner, other.history);
}
// copy factory form
static Account copyOf(Account other) {
return new Account(other);
}
}go deeper
Can say clone() is discouraged and that a copy constructor is the usual alternative.
Lists the main flaws (shallow, checked exception, marker-interface oddity) and writes a copy constructor instead of implementing Cloneable.
Gives the full Effective Java critique including constructor-bypass / final-field clash, and articulates the concrete advantages of copy constructors/factories plus the array exception.
Sets the org-wide convention (copy constructors/factories, immutability-first), recognizes the rare polymorphic-copy gap and how to bridge it, and knows where platform constraints still mandate clone.
## The indictment of Cloneable/clone() *Effective Java* (Item 13, 'Override clone judiciously') argues the whole mechanism is broken. The specific charges: 1. **Broken marker-interface contract.** `Cloneable` declares **no methods**, yet implementing it changes what the *protected* `Object.clone()` does (copy vs. throw). A marker interface that silently modifies a method on a *different* class is a design anomaly — implementing an interface normally adds capability, not alters an inherited method's behavior. 2. **Shallow by default.** `clone()` copies fields bit-for-bit, so reference fields are **shared**. Authors must remember to deep-copy every mutable field, and any miss is a silent aliasing bug. 3. **Checked exception for nothing.** `clone()` declares `throws CloneNotSupportedException`, which a `Cloneable` class can never actually trigger — so every call/override is cluttered with handling for an impossible case. 4. **Bypasses constructors.** No constructor runs, so invariant checks are skipped and you cannot deep-copy into **final** fields. This makes `clone()` essentially incompatible with the recommended immutable, all-final design. 5. **Fragile under inheritance.** A correct `clone()` requires every class in the hierarchy to call `super.clone()` and deep-copy its own mutable fields; a subclass that forgets silently shares state. Designing a class for inheritance *and* `Cloneable` is especially painful. ## The recommended alternative: copy constructor / copy factory A **copy constructor** takes an instance of the same class and copies it: ```java public Foo(Foo other) { /* copy / deep-copy fields */ } ``` A **copy factory** is the static-method form: ```java public static Foo copyOf(Foo other) { return new Foo(other); } ``` Why they are better: - **Real construction** — invariants are validated; the object is built the normal way. - **Works with `final` fields and immutability** — deep-copied values are passed straight to the constructor, so fields stay `final`. - **No broken contract, no checked exception** — they rely on nothing from `Cloneable`. - **Can accept an interface type** (a *conversion* constructor) — e.g. `new ArrayList<>(someCollection)` copies any `Collection` into an `ArrayList`. `clone()` always returns the source's exact runtime class and cannot convert. - **Easier to reason about / test** — ordinary method, no native magic. Trade-off: a copy constructor/factory cannot be invoked polymorphically through a base type the way an overridden `clone()` can (you must know the concrete type or provide your own copy-via-interface method). In practice this is rarely a real limitation. ## When clone() is still acceptable - **Arrays:** `array.clone()` is the correct, idiomatic way to copy an array (it returns the proper array type, no cast). Arrays' `clone()` is well-behaved, and there is no copy-constructor alternative for them. - **Interop:** implementing `Cloneable` because a legacy framework or API contract requires it. ## One-line takeaway The `Cloneable` mechanism is a flawed, error-prone, constructor-bypassing API; prefer a **copy constructor** or **copy factory**, and use `clone()` only for arrays or when an external contract forces it.
- What is one thing clone() can do that a copy constructor cannot?clone() can be invoked polymorphically through a supertype reference and returns an object of the source's exact runtime class, so generic code can copy 'whatever this actually is' without knowing the concrete type. A copy constructor must name a concrete class. (In practice you work around this with a copy method or a registry; the limitation is minor.)
- Is using array.clone() considered bad practice?No. Arrays are the well-behaved exception: array.clone() returns the correctly typed array with no cast, and there is no copy-constructor alternative for arrays, so it is the idiomatic way to copy one (a shallow copy of the elements).
saying these in an interview costs you the question
- Recommending clone() as the default way to copy objects
- Not knowing the copy-constructor / copy-factory alternative
- Claiming clone() works fine with immutable, all-final classes
- Forgetting that array.clone() is the legitimate, idiomatic exception