Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to copy an object

Short answer

The clearest way is a copy constructor that takes an object of the same class:

class Settings {
    String theme;
    int fontSize;
 
    Settings(String theme, int fontSize) {
        this.theme = theme;
        this.fontSize = fontSize;
    }
 
    Settings(Settings other) {
        this(other.theme, other.fontSize);
    }
}
 
void main() {
    var original = new Settings("dark", 14);
    var copy = new Settings(original);
    copy.fontSize = 18;
 
    IO.println(original.fontSize + " " + copy.fontSize);
}

Output:

14 18

Records need no copying

An immutable object can be shared without copies. For a "modified copy", create a new object:

record Settings(String theme, int fontSize) {
    Settings withFontSize(int size) {
        return new Settings(theme, size);
    }
}
 
void main() {
    var original = new Settings("dark", 14);
    IO.println(original.withFontSize(18));
    IO.println(original);
}

Output:

Settings[theme=dark, fontSize=18]
Settings[theme=dark, fontSize=14]

A deep copy

If the object contains a mutable list, copy it too, otherwise both copies share one list:

class Playlist {
    String name;
    List<String> songs;
 
    Playlist(String name, List<String> songs) {
        this.name = name;
        this.songs = songs;
    }
 
    Playlist(Playlist other) {
        this(other.name, new ArrayList<>(other.songs));
    }
}
 
void main() {
    var original = new Playlist("Road", new ArrayList<>(List.of("Song A")));
    var copy = new Playlist(original);
    copy.songs.add("Song B");
 
    IO.println(original.songs);
    IO.println(copy.songs);
}

Output:

[Song A]
[Song A, Song B]

Common mistake

Assigning the object to another variable. It is not a copy: both variables point to the same object:

class Counter {
    int value;
}
 
void main() {
    var a = new Counter();
    var b = a;
    b.value = 10;
 
    IO.println(a.value);
}

Output:

10

The clone() method exists too, but it is awkward: you need the Cloneable interface, a cast and exception handling. In new code use a copy constructor or records.

Functions used in this recipe

  • record — Declares a record — an immutable data class with ready-made equals(), hashCode() and toString().
  • List.copyOf() — Creates an unmodifiable list copy of a collection.
  • Cloneable — A marker interface that allows Object.clone(). New code uses copy constructors instead.

Thanks for reading!

Donate to the site — we work hard for you.