| Claim | Verdict |
|---|
| A copy constructor always deep copies | False. It copies whatever you tell it to. |
| It needs a special keyword | False. Its own type as parameter is the signal. |
new ArrayList<>(other) is deep | False. It copies the container only. |
| Subclasses inherit it | False. Constructors are never inherited. |
| Sharing a String is a bug | False. Immutable targets are safe to share. |
clone() can set final fields | False. It bypasses construction. |
| It works on arrays | False. Arrays have no constructors, so they use clone(). |
| It is always deep enough | Only if every mutable field was handled. |
Frequently Asked Questions
How do I recognise a copy constructor?
By its shape, not by any keyword. A constructor taking exactly one parameter of its own class type is a copy constructor, which means overload resolution picks it the same way it picks any other constructor. There is no interface to implement and no annotation to add.
How do I make a copy constructor deep?
Handle every mutable field individually. Copy primitives and immutable references by plain assignment, clone primitive arrays, build a new collection from the old one, and then copy each element inside it when those elements are mutable. Copying the container without copying its contents leaves a shallow copy no matter how the container was built.
Why is sharing a String field safe but sharing a list is not?
Because immutability is what makes sharing harmless. A String cannot be altered, so two objects holding the same String reference observe no difference. An ArrayList can be altered through either reference, so both objects see the change and neither object is independent.
Why prefer a copy constructor over clone?
Because a copy constructor is a real constructor, so it runs the superclass chain, assigns final fields, needs no casting, and throws no checked exception. The clone method bypasses all constructors, so invariants are never established, final fields cannot be set, and the result requires a cast.
Can a subclass use the parent copy constructor?
Not automatically, since constructors are not inherited. Calling super with a parent-typed parameter works, because a subclass instance is also a parent instance. Passing the subclass-typed parameter does not compile unless you add an overload or cast explicitly.
How do I copy a two-dimensional array?
With a loop, because clone on a two-dimensional array copies only the outer level of row references. Iterate over the rows and clone each one individually to reach a genuine deep copy, using a separate loop for jagged arrays whose rows differ in length.
Is a copy constructor needed for an immutable class?
Usually not, since you can construct a fresh instance from the accessors whenever one is needed. It is still reasonable to keep when construction performs validation, because the copy constructor centralises that logic and, unlike clone, it may assign final fields.
What about Optional fields?
Plain assignment is sufficient. An Optional instance is immutable, so sharing the reference between two objects cannot produce the shared-state bug that affects mutable fields.