Short answer
A shallow copy duplicates the top-level object but shares references to nested mutable objects, so mutating a nested list affects both copies; a deep copy recursively clones the nested objects so they are fully independent.
Explanation
A copy constructor must deep-copy any mutable fields (lists, dates, arrays) or it silently produces aliasing bugs. In practice I prefer copy constructors or static 'copyOf' factories over Cloneable, since clone() is broken by design (no constructor call, shallow by default, awkward checked exception).
Common mistakes
- Thinking a copy constructor automatically deep-copies nested objects.
- Sharing mutable collections between the original and the copy.