What is the copy constructor pattern in Java, and how do you implement a correct one?
answer
- Constructor whose param is the same class
- Java does NOT auto-generate it (unlike C++)
- Shallow = share reference, deep = clone referenced object
- Immutable fields safe to share
- Prefer over Cloneable/clone()
basics
~20 sA copy constructor takes another object of the same class and creates a new object with the same values. You write a constructor whose single parameter is the same type, then copy each field into the new object.
solid answer
~40 sA copy constructor is a constructor that takes one argument of the same class and produces a new instance holding copies of that argument's state. Java has no built-in copy constructor (unlike C++), so you write one explicitly: `public Point(Point other) { this.x = other.x; this.y = other.y; }`. For fields that are mutable reference types you must decide between a shallow copy (copy the reference) and a deep copy (clone the referenced object), otherwise the new object shares mutable state with the original. The copy-constructor idiom is generally preferred over `Cloneable`/`clone()` because it is type-safe, needs no cast, doesn't rely on the broken `Object.clone()` protocol, can run constructor logic and final-field assignment, and lets the caller choose the concrete type.
code
java · 15 linespublic final class Team {
private final String name; // immutable: safe to share
private final List<String> members; // mutable: must deep-copy
public Team(String name, List<String> members) {
this.name = name;
this.members = new ArrayList<>(members);
}
// Copy constructor
public Team(Team other) {
this.name = other.name;
this.members = new ArrayList<>(other.members); // independent copy
}
}go deeper
Can write a constructor that takes the same type and copies primitive fields across; knows Java doesn't generate one automatically.
Distinguishes shallow vs deep copy, correctly deep-copies mutable collections, and leaves immutable fields shared.
Articulates why copy constructors/factories beat Cloneable/clone(), handles the inheritance/slicing limitation, and chooses a copy factory when polymorphism matters.
Sets team conventions for copying (immutability-first design that often removes the need to copy at all), weighs defensive-copy cost vs immutable value objects/records, and reasons about copy semantics across module boundaries.
## What problem are we solving? Sometimes you have an existing object and want a brand-new, independent object that starts with the same data. For example, you have a `Point(x=3, y=4)` and want a second point with the same coordinates that you can move around without affecting the first. The mechanism Java offers for this is the **copy constructor**. ## What is a constructor? A **constructor** is a special method that runs when you create an object with the `new` keyword. It has the same name as the class and no return type. Its job is to initialize the new object's fields (its internal variables). ## What is a copy constructor? A **copy constructor** is simply a constructor whose single parameter is *another object of the same class*. Inside it, you copy each field from that other object into the object being created: ```java public class Point { private final int x; private final int y; public Point(int x, int y) { // normal constructor this.x = x; this.y = y; } public Point(Point other) { // copy constructor this.x = other.x; this.y = other.y; } } ``` Note: Java does **not** generate a copy constructor for you (this is different from C++). If you want one, you write it. ## Shallow vs deep copy — the key subtlety A field can hold either a *value* (like an `int`) or a *reference* (a pointer to another object, like a `List` or an array). When you copy a reference, you copy the arrow, not the thing it points to. - **Shallow copy:** copy the reference. The new object and the original now share the *same* underlying object. If that shared object is mutable, changing it through one affects the other. - **Deep copy:** create a fresh copy of the referenced object too, so the two are fully independent. ```java public class Team { private final String name; private final List<String> members; public Team(Team other) { this.name = other.name; // String is immutable: sharing is safe this.members = new ArrayList<>(other.members); // DEEP copy: independent list } } ``` If you had written `this.members = other.members;` (shallow), adding a member to the copy would also add it to the original — usually a bug. Immutable types (like `String`, `Integer`, `LocalDate`) are safe to share, so you don't need to deep-copy them. ## Why prefer copy constructors over clone()? Java has an older copying mechanism: implement `Cloneable` and override `Object.clone()`. It is widely considered broken: - `clone()` returns `Object`, so callers must cast. - `Cloneable` is a marker interface that doesn't actually declare `clone()`, so the contract is awkward. - `Object.clone()` bypasses constructors, which can leave invariants or `final` fields in odd states. A copy constructor avoids all of this: it is ordinary, type-safe code; it runs real constructor logic; it can assign `final` fields; and a copy *factory method* variant (`static Point copyOf(Point p)`) can even return a chosen subtype. Joshua Bloch's *Effective Java* explicitly recommends copy constructors/factories over `Cloneable`. ## A caveat with inheritance A copy constructor only knows about the exact type it is written for. If you call `new Animal(someDog)` where `someDog` is actually a `Dog`, you get a plain `Animal`, losing the dog-specific state (this is sometimes called *slicing*). A copy *factory* that delegates, or a polymorphic `copy()` method overridden per subclass, addresses this when needed.
- When is a shallow copy actually fine?When all the copied reference fields point to immutable objects (String, Integer, LocalDate, etc.) or when sharing is genuinely intended. Immutable objects can't be changed, so sharing them is safe.
- Why does Effective Java recommend copy constructors over clone()?clone() is type-unsafe (returns Object), relies on the awkward Cloneable marker interface, bypasses constructors so final fields and invariants are fragile, and has a fragile contract. Copy constructors are plain type-safe code that runs real constructor logic.
saying these in an interview costs you the question
- Thinking Java auto-generates a copy constructor like C++ does
- Doing a shallow copy of a mutable collection and assuming the copy is independent
- Believing clone() is the recommended way to copy objects in modern Java
- Deep-copying immutable fields like String unnecessarily