What is wrong with Java's Cloneable mechanism, and why does Effective Java say to override clone() only judiciously?
answer
- Cloneable = empty marker; clone() lives on Object (protected)
- Shallow copy → shared mutable fields
- Bypasses constructors → invariants skipped
- final fields block deep copy
- Prefer copy constructor / copy factory; arrays are the exception
basics
~20 sCloneable is a marker interface that doesn't declare clone(); clone() lives on Object as a protected method that throws unless you implement Cloneable. The mechanism is awkward — it makes a shallow copy, bypasses constructors, and is hard to do correctly — so prefer copy constructors or copy factories.
solid answer
~50 sCloneable is a marker interface with no methods; the clone() method is actually a protected, native method on Object that throws CloneNotSupportedException unless the class implements Cloneable. That's a strange contract: the interface changes the behavior of a method it doesn't even declare. Object.clone() returns a field-by-field shallow copy that bypasses constructors, so any invariants enforced in the constructor are skipped, and mutable fields (arrays, collections) are shared between original and clone unless you deep-copy them manually. final mutable fields can't be reassigned to a deep copy, so making a class properly cloneable can force you to drop final. Because of all this, Effective Java recommends a copy constructor (new T(T other)) or a static copy factory instead — they're cleaner, don't rely on the broken Cloneable contract, don't throw checked exceptions, can take interface-typed arguments, and don't conflict with final fields.
go deeper
Knows clone() makes a shallow copy and that copy constructors are an alternative; may not know the Cloneable contract details.
Can write a correct clone() with super.clone() and deep-copy of mutable fields, and explain shallow vs deep copy.
Articulates all the Cloneable flaws (marker-changes-other-method's-behavior, constructor bypass, final-field conflict, inheritance burden) and argues for copy constructors/factories, noting arrays as the exception.
Decides clone-vs-copy-constructor policy for a codebase/library, weighs immutability and inheritance design, and knows when an immutable type needs no copy at all.
## Goal: making a copy of an object Sometimes you need a second object equal to an existing one but independent of it — a *copy*. Java's oldest built-in answer is the `Cloneable`/`clone()` mechanism, and *Effective Java* explains why it is so flawed that you should usually avoid it. ## How the mechanism actually works (and why it's strange) A **marker interface** is an interface with no methods that exists only to *tag* a class so other code can check `instanceof` (or, here, so the JVM can check it). `Cloneable` is such a marker — it declares nothing. The `clone()` method does **not** live on `Cloneable`. It lives on `java.lang.Object` as `protected native Object clone()`. Its contract: if the object's class implements `Cloneable`, `Object.clone()` returns a **field-by-field copy** of the object; if the class does **not** implement `Cloneable`, it throws `CloneNotSupportedException` (a *checked* exception). So `Cloneable` is a marker interface that changes the behavior of a `protected` method on a *different* type — a highly unusual and fragile design. To expose cloning, you must override `clone()`, make it `public`, change its return type to your own class (a *covariant return type*, allowed since Java 5), call `super.clone()`, and typically catch the impossible `CloneNotSupportedException`. ## Flaw 1: shallow copy shares mutable state `Object.clone()` copies each field's *value*. For a reference field, the value is the reference (the pointer), so the original and the clone end up pointing at the **same** nested object. This is a **shallow copy**. If that nested object is mutable — an array, an `ArrayList`, a `Date` — then mutating it through one copy is visible through the other, silently coupling two objects that callers think are independent. To fix this you must perform a **deep copy**: after `super.clone()`, replace each mutable field with a clone/copy of its own: ```java @Override public Stack clone() { try { Stack result = (Stack) super.clone(); result.elements = elements.clone(); // deep-copy the backing array return result; } catch (CloneNotSupportedException e) { throw new AssertionError(e); // can't happen — we implement Cloneable } } ``` For nested mutable structures (an array of lists, a linked list) a simple `array.clone()` isn't enough; you may need recursion or iteration, which is easy to get wrong. ## Flaw 2: clone() bypasses constructors `Object.clone()` produces an object *without running any constructor*. Every invariant your constructor establishes (validation, normalization, registering with a registry, assigning an ID) is **skipped**. A clone can therefore be in a state the constructor would never have allowed. ## Flaw 3: final fields If a mutable field is `final`, you *cannot* reassign it to a deep copy inside `clone()` (final fields can only be set in construction). So making a class correctly cloneable can force you to remove `final` from fields that ought to be final — weakening immutability for the sake of a broken mechanism. ## Flaw 4: inheritance and the super.clone() contract A class designed for inheritance that implements `Cloneable` imposes a heavy burden: every subclass must also clone correctly, and `clone()` must call `super.clone()` (not `new`) so the runtime type is right. Skipping `super.clone()` breaks subclasses' clones. This contract is delicate and rarely documented well. ## The recommended alternative: copy constructor / copy factory A **copy constructor** takes an instance of the same class and copies it: `public Foo(Foo other) { ... }`. A **copy factory** is the static-method form: `public static Foo newInstance(Foo other) { ... }`. (`ArrayList`, `HashMap`, `TreeSet`, etc. all provide copy constructors.) These beat `Cloneable` on every axis: - They don't depend on the bizarre `Cloneable` contract or a risky extralinguistic object-creation mechanism. - They **don't** throw checked exceptions and require no casts. - They **don't** conflict with `final` fields — you set them normally in the constructor. - They can accept an **interface** type (a *conversion constructor*/*conversion factory*), e.g. `new TreeSet<>(someCollection)`, so you can copy *and* change representation. - Construction runs normally, so all invariants hold. ## So when is clone() OK? Arrays are the one place `clone()` is genuinely the idiomatic, fast way to copy (`arr.clone()` returns an array of the same runtime type). For everything else, *Effective Java*'s guidance is: don't implement `Cloneable`; if you must (e.g. extending a class that already does), follow the `super.clone()` + deep-copy recipe carefully. Otherwise, provide a copy constructor or copy factory.
- What does the covariant return type buy you when overriding clone()?Since Java 5 an override may return a subtype of the original return type. Overriding clone() to return your concrete class instead of Object means callers don't need to cast the result, making the API far more pleasant to use.
- How do copy constructors let you convert between representations?A copy/conversion constructor can take an interface-typed argument. For example new TreeSet<>(aHashSet) copies the elements while switching the implementation from hash-based to tree-based — something clone(), which preserves the exact runtime class, cannot do.
saying these in an interview costs you the question
- Saying Cloneable declares the clone() method (it declares nothing)
- Assuming Object.clone() makes a deep copy
- Forgetting that clone() bypasses constructors
- Implementing clone() without calling super.clone() (breaks subclass clones)
- Claiming copy constructors can't change the underlying representation