00:00

Copy Constructor in Java – Explained with Examples

Last updated: 7 min read

A copy constructor creates a new object as a copy of an existing object of the same class: Point copy = new Point(original);. Java does not generate copy constructors automatically, as C++ does, but writing one is the simplest and clearest way to duplicate an object in Java.

This tutorial shows how to write copy constructors, explains the crucial difference between shallow and deep copies, introduces defensive copying, and compares copy constructors with clone().

1. Why Copy Objects?

In Java, assigning one variable to another (b = a) copies only the reference: both variables point to the same object, and a change through one is visible through the other. When you need an independent object, for example to modify a copy while keeping the original, or to protect your class's data, you need a real copy.

2. Writing a Copy Constructor

A copy constructor takes one parameter of the same class and copies its fields:

CopyConstructorBasics.java
public class CopyConstructorBasics {
    static class Point {
        int x, y;
        Point(int x, int y) { this.x = x; this.y = y; }
        Point(Point other) {                 // copy constructor
            this.x = other.x;
            this.y = other.y;
        }
        @Override public String toString() { return "(" + x + ", " + y + ")"; }
    }

    public static void main(String[] args) {
        Point original = new Point(3, 4);
        Point copy = new Point(original);     // a new, independent object
        Point alias = original;               // NOT a copy: same object

        copy.x = 100;
        alias.y = 50;

        System.out.println("original = " + original);
        System.out.println("copy     = " + copy);
        System.out.println("original == copy: " + (original == copy));
    }
}
Output
original = (3, 50)
copy     = (100, 4)
original == copy: false

Changing copy did not affect original, but changing alias did, because alias is just another name for the same object.

3. Shallow Copy vs Deep Copy

Copying fields works perfectly for primitives and immutable objects such as String. But if a field refers to a mutable object, such as a list or an array, copying the reference means both objects share it. That is a shallow copy. A deep copy also copies those mutable objects:

ShallowVsDeep.java
import java.util.ArrayList;
import java.util.List;

public class ShallowVsDeep {
    static class Playlist {
        String name;
        List<String> songs;

        Playlist(String name, List<String> songs) {
            this.name = name;
            this.songs = songs;
        }

        // Shallow copy: the list itself is shared
        static Playlist shallowCopy(Playlist p) {
            return new Playlist(p.name, p.songs);
        }

        // Copy constructor doing a deep copy: a new list with the same songs
        Playlist(Playlist other) {
            this.name = other.name;                       // String is immutable: sharing is safe
            this.songs = new ArrayList<>(other.songs);    // mutable list: copy it
        }
    }

    public static void main(String[] args) {
        Playlist original = new Playlist("Road trip", new ArrayList<>(List.of("Song A", "Song B")));

        Playlist shallow = Playlist.shallowCopy(original);
        Playlist deep = new Playlist(original);

        original.songs.add("Song C");

        System.out.println("original: " + original.songs);
        System.out.println("shallow:  " + shallow.songs + "   <- changed too (shared list)");
        System.out.println("deep:     " + deep.songs + "   <- independent");
    }
}
Output
original: [Song A, Song B, Song C]
shallow:  [Song A, Song B, Song C]   <- changed too (shared list)
deep:     [Song A, Song B]   <- independent
Field typeWhat the copy constructor should do
Primitives (int, double…)Copy the value
Immutable objects (String, Integer, records, LocalDate)Copy the reference; sharing is safe
Mutable collectionsCreate a new collection: new ArrayList<>(other.list)
Arraysother.array.clone() or Arrays.copyOf()
Your own mutable objectsCall their copy constructors

4. Defensive Copies

A class that stores a mutable object passed in by a caller, or returns one from a getter, can be modified from outside without noticing. Defensive copies on the way in and out protect the object's state:

DefensiveCopy.java
import java.util.Arrays;

public class DefensiveCopy {
    static final class Schedule {
        private final int[] days;

        Schedule(int[] days) {
            this.days = days.clone();          // copy in: caller cannot change our data later
        }

        Schedule(Schedule other) {             // copy constructor
            this(other.days);
        }

        int[] getDays() { return days.clone(); }   // copy out: caller cannot change our data
    }

    public static void main(String[] args) {
        int[] input = {1, 3, 5};
        Schedule s = new Schedule(input);
        input[0] = 99;                         // does not affect s

        int[] fromGetter = s.getDays();
        fromGetter[1] = 77;                    // does not affect s either

        System.out.println("schedule days: " + Arrays.toString(s.getDays()));
        System.out.println("copy of schedule: " + Arrays.toString(new Schedule(s).getDays()));
    }
}
Output
schedule days: [1, 3, 5]
copy of schedule: [1, 3, 5]

The caller changed both the original input array and the array returned by the getter, but the schedule stayed the same. The copy constructor reuses the main constructor with this(other.days), which already makes the copy.

5. Copy Constructor vs clone()

FeatureCopy constructorclone()
Interface neededNoneCloneable
Checked exceptionNoCloneNotSupportedException must be handled
Return typeThe exact class, no castObject unless overridden covariantly
Works with final fieldsYesHard: fields are copied before your code runs
Control over deep copyingFull and explicitMust override and fix up fields manually
RecommendedYes (also static factories like copyOf())Mostly for arrays

Joshua Bloch's Effective Java recommends copy constructors or copy factories over clone(). For arrays, clone() is still the simplest choice. See Object Cloning in Java.

6. When You Do Not Need Copies

Immutable objects never need copying, because nobody can change them. And the JDK collections already provide copy constructors and copy factories:

CopyAlternatives.java
import java.util.ArrayList;
import java.util.List;

public class CopyAlternatives {
    record Address(String city, String pin) { }

    public static void main(String[] args) {
        // Immutable objects such as records never need copying: share them freely
        Address home = new Address("Pune", "411001");
        Address same = home;
        System.out.println("records can be shared: " + same);

        // Collections have copy constructors and copy factories
        List<String> names = new ArrayList<>(List.of("Asha", "Ravi"));
        List<String> mutableCopy = new ArrayList<>(names);     // copy constructor
        List<String> readOnlyCopy = List.copyOf(names);        // immutable copy (Java 10+)
        names.add("Meera");
        System.out.println("names:        " + names);
        System.out.println("mutableCopy:  " + mutableCopy);
        System.out.println("readOnlyCopy: " + readOnlyCopy);
    }
}
Output
records can be shared: Address[city=Pune, pin=411001]
names:        [Asha, Ravi, Meera]
mutableCopy:  [Asha, Ravi]
readOnlyCopy: [Asha, Ravi]

7. Copy Constructors and Inheritance

A subclass copy constructor should call the parent's copy constructor with super(other) and then copy its own fields. Note that a copy constructor always creates an object of the class it belongs to: new Animal(dog) creates an Animal, not a Dog. When the exact runtime type must be preserved, a polymorphic copy() method is the better tool.

8. Summary

  • A copy constructor takes an object of the same class and creates an independent copy.
  • Java does not create copy constructors automatically; you write them.
  • Copy mutable fields (collections, arrays, mutable objects) to get a deep copy.
  • Use defensive copies in constructors and getters to protect internal state.
  • Prefer copy constructors or copy factories over clone(), and immutable objects over copying.

Related Tutorials