Object Cloning in Java

Naveen AnamaneniUpdated · 5 min read

Navika has a class timetable, and Srihitha wants one just like it, then plans to change a period or two. Writing Timetable copy = original; doesn't copy anything: both variables would point at the same object. Java's built-in way to duplicate an object is clone(), inherited from Object. It's quick to use, but its default copy is shallow, which leads to one of the classic Java bugs.

Shallow Copy, Then Deep Copy

Shallow copies share inner objects; deep copies don't
Cloning.java▶ Try it
import java.util.Arrays;
 
public class Cloning {
    static class Timetable implements Cloneable {
        String owner;
        String[] periods;
 
        Timetable(String owner, String[] periods) {
            this.owner = owner;
            this.periods = periods;
        }
 
        @Override
        public Timetable clone() {
            try {
                return (Timetable) super.clone();
            } catch (CloneNotSupportedException e) {
                throw new AssertionError(e);
            }
        }
 
        Timetable deepCopy() {
            Timetable copy = clone();
            copy.periods = periods.clone();
            return copy;
        }
    }
 
    static void print(Timetable t) {
        System.out.println(t.owner + " " + Arrays.toString(t.periods));
    }
 
    public static void main(String[] args) {
        Timetable navika = new Timetable("Navika",
            new String[] {"Math", "Physics", "English"});
 
        Timetable shallow = navika.clone();
        shallow.owner = "Srihitha";
        shallow.periods[0] = "Chemistry";
        print(navika);
        print(shallow);
 
        Timetable deep = navika.deepCopy();
        deep.owner = "Advitha";
        deep.periods[1] = "Biology";
        print(navika);
        print(deep);
    }
}
Output
Navika [Chemistry, Physics, English]
Srihitha [Chemistry, Physics, English]
Navika [Chemistry, Physics, English]
Advitha [Chemistry, Biology, English]

How it works

  1. implements Cloneable switches on Object.clone() for this class. Without it, super.clone() throws CloneNotSupportedException (see "Marker Interfaces in Java").
  2. The override is public (the original is protected) and returns Timetable (a covariant return), so callers don't need a cast.
  3. super.clone() creates a new object and copies each field as is. owner is a reference to an immutable String, so changing it on the copy is harmless. But periods is a reference to an array, and both objects now share that one array.
  4. So shallow.periods[0] = "Chemistry" changes Navika's timetable too. That's the shallow-copy bug.
  5. deepCopy() also copies the array (periods.clone()), so the change to Advitha's copy doesn't leak back into Navika's timetable.

Shallow vs Deep

Shallow copyDeep copy
New outer objectYesYes
Primitive fieldsCopiedCopied
References to immutable objects (String, Integer)Shared, which is safeShared, which is safe
References to mutable objects (arrays, lists, Date)Shared: changes leak between copiesCopied: fully independent
CostCheapMore work and memory

Why Many Developers Avoid clone()

clone() has a long list of quirks: Cloneable has no clone method of its own, Object.clone is protected, it throws a checked exception you must catch, it bypasses constructors, and it doesn't work with final fields that need new values. Simpler alternatives:

AlternativeExample
Copy constructornew Timetable(original) (see "Copy Constructor")
Static copy factoryTimetable.copyOf(original)
Immutable objectsNothing to copy: share freely (see "How to Create an Immutable Class in Java")
Collection copiesnew ArrayList<>(list), List.copyOf(list), array.clone()

Common Mistakes

Assuming clone() is deep. Any mutable field needs its own copy.

Forgetting implements Cloneable. The code compiles, then super.clone() throws at runtime.

Leaving clone() protected. Outside code can't call it; override it as public.

Interview Corner

What is the difference between shallow and deep copy?

A shallow copy creates a new object and copies field values, so referenced objects are shared between the original and the copy. A deep copy also creates copies of the referenced mutable objects, recursively, so the two are completely independent. Object.clone() performs a shallow copy.

Why is Cloneable called a broken interface?

It's a marker with no clone method, so implementing it doesn't make clone public or callable. Object.clone is protected, throws a checked CloneNotSupportedException, creates objects without calling constructors, and is shallow. Copy constructors or static factories are usually clearer and safer.

Practice

  1. Easy: Clone an int[] with clone(), change the copy, and show the original is unchanged.
  2. Harder: Give Timetable a List<String> notes field. Update deepCopy() so the notes list is copied too, and prove it with a test in main.

Quick check: Cloning

4 questions
1What kind of copy does Object.clone() make?
2What happens if a class doesn't implement Cloneable and calls super.clone()?
3In a shallow copy, which field change affects the original?
4Which is usually a clearer alternative to clone()?

Key Takeaways

Was this tutorial helpful?

Lesson 155 of 482