skip to content

What is the Prototype design pattern, and how is it expressed in Java with Object.clone() and Cloneable?

level: juniorimportance: should knowfreq 55%

answer

  1. Copy a template instead of constructing from scratch
  2. Cloneable = marker interface, no methods
  3. clone() lives on Object, is protected, shallow
  4. Override: super.clone(), make public, covariant return
  5. Prefer copy constructor / copy factory

basics

~10 s

Prototype creates new objects by copying an existing instance instead of building one from scratch. In Java you implement Cloneable and override clone() to return a copy of the object.

solid answer

~40 s

Prototype is a creational pattern: instead of calling a constructor, you take an existing object (the prototype) and copy it to produce a new one. It is useful when creating an object is expensive or when you want a pre-configured template you can duplicate. Java has built-in support: Object.clone() performs a field-by-field copy, but it only works if the class implements the marker interface Cloneable, otherwise clone() throws CloneNotSupportedException. By convention you override clone(), make it public, call super.clone(), and return the copy. The catch is that the JDK's mechanism is widely considered flawed, so many developers prefer copy constructors or copy factories instead.

code

java · 16 lines
java
class Point implements Cloneable {
    int x, y;
    Point(int x, int y) { this.x = x; this.y = y; }

    @Override
    public Point clone() {                 // public + covariant return
        try {
            return (Point) super.clone();  // Object.clone() -> shallow copy
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(e);    // unreachable: we implement Cloneable
        }
    }
}

Point a = new Point(1, 2);
Point b = a.clone();   // new object with x=1, y=2

go deeper

for a junior

Can state that Prototype copies an existing object and that Java does this with Cloneable + clone(), and knows clone() is shallow by default.

for a middle

Explains the marker-interface mechanism, the override recipe (super.clone, public, covariant return), and when copying beats constructing.

for a senior

Articulates why clone() is shallow, why CloneNotSupportedException exists, and when Prototype is genuinely useful versus a factory.

for a principal

Frames Prototype as an abstraction over object creation, weighs it against builders/factories/copy constructors, and reasons about its place in extensible/plugin designs where concrete types aren't known at compile time.

## The problem Prototype solves Normally you create an object by calling a **constructor**: `new Foo(...)`. The **Prototype pattern** is a *creational* design pattern (a pattern about how objects get made) that says: instead of constructing a brand-new object from scratch, take an existing object — the **prototype** — and **copy** it to make a new one. The prototype acts as a template. Why bother? Two main reasons: 1. **Construction is expensive.** If building an object requires a database call, heavy computation, or parsing, copying a ready-made one is cheaper. 2. **You want pre-configured variants.** You can keep a registry of fully set-up prototype objects and clone whichever you need, instead of remembering all the constructor arguments. ## How Java expresses it Java ships with a built-in copy mechanism on the root class `Object`: - `protected Object clone()` — a method on `Object` that produces a **shallow copy**: it allocates a new object and copies every field's value across, field by field. - `Cloneable` — a **marker interface** (an interface with no methods; it just *marks* a class as opting in). If a class does **not** implement `Cloneable`, calling `clone()` throws `CloneNotSupportedException`. So the standard recipe is: 1. Declare `class Foo implements Cloneable`. 2. Override `clone()`, widen its visibility from `protected` to `public`, and (by convention) narrow its return type to `Foo` (called a *covariant return type*). 3. Inside, call `super.clone()`, which ultimately reaches `Object.clone()` and does the actual field copy. ```java class Point implements Cloneable { int x, y; @Override public Point clone() { try { return (Point) super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError(e); } } } ``` ## Key terms defined - **Marker interface:** an interface with no members, used purely to tag a class so code (or the JVM) can check `instanceof`. `Cloneable` is the classic example. - **Shallow copy:** copies the top-level fields. If a field is a reference to another object (a list, an array), the copy shares the *same* referenced object — both point at it. - **Deep copy:** also copies the objects the fields point to, recursively, so the copy is fully independent. - **Covariant return type:** an overriding method may return a subtype of the original return type; that lets `clone()` return `Point` instead of `Object`, so callers avoid casting. ## Why it is considered tricky `Cloneable` does *not* contain the `clone` method — that lives on `Object` and is `protected`. So `Cloneable` only changes the *behavior* of a method declared elsewhere. `Object.clone()` always makes a *shallow* copy, which is wrong for any object holding mutable references. For these reasons, Effective Java recommends **copy constructors** or **copy factories** over `clone()` in most code. The Prototype *idea* (copy a template) is sound; Java's specific `clone()` *mechanism* is the part people avoid.

  • Why does clone() throw CloneNotSupportedException if Cloneable has no methods?
    Cloneable is a marker interface that Object.clone() checks via instanceof at runtime. If the object isn't an instance of Cloneable, Object.clone() throws CloneNotSupportedException; the interface enables the behavior rather than declaring the method.
  • Why widen clone() to public and narrow its return type?
    Object.clone() is protected, so callers outside the package/class can't use it; overriding it as public exposes copying. Narrowing the return type (covariant return) to the actual class spares callers from casting.

A prototype is like a rubber stamp: instead of hand-drawing the same shape each time, you press a copy of a master template. But Java's built-in stamp only copies the outline (shallow), not what's drawn inside.

saying these in an interview costs you the question

  • Thinking Cloneable declares the clone() method (it doesn't — clone is on Object)
  • Assuming clone() makes a deep copy (it is shallow)
  • Claiming you must always use clone() for Prototype — the pattern is about copying, not specifically clone()
  • Forgetting that without Cloneable, clone() throws CloneNotSupportedException

context