Clone() method in Java
This post will discuss how to copy an object in Java using the clone() method in Object class and one provided by Apache Commons Lang. We will also discuss shallow copy and deep copy in detail.
Cloning an object creates a copy of an existing object to modify or move the copied object without impacting the original object. In Java, objects are manipulated through reference variables, and there is no operator for actually copying an object. Remember that the assignment operator duplicates the reference, not the object.
1. Using Object.clone() method
Classes that want copying functionality can use Object.clone() method, which creates and returns a copy of the object. The prototype of the Object.clone() is
|
1 |
protected Object clone() throws CloneNotSupportedException; |
As the return type of Object.clone() is Object, typecasting is needed to assign the returned Object reference to a reference to an object.
All classes involved must implement the Cloneable interface to indicate to the Object.clone() method that it is legal for that method to make a field-for-field copy of instances of that class. Invoking Object’s clone method on an instance that does not implement the Cloneable interface results in the CloneNotSupportedException.
Since every class implicitly extends Object class, Object.clone() is an overridable method. Since Java provides support for covariant return types, the return type of clone() can be changed from Object to the type of the object being cloned, and clone() should override the protected Object.clone() method with a public method.
The clone() behaves similarly as a Copy Constructor. It calls the clone() method of its parent class to obtain the copy, etc., until it eventually reaches Object’s clone() method, which creates a new instance of the same class as the object copies all the fields to the new instance.
Cons:
1. Object.clone() will not work on interfaces and abstract classes.
The only way to use the Object.clone() method is if the class of an object is known, i.e., we cannot access the clone() method on an abstract type since most interfaces and abstract classes in Java do not specify a public clone() method.
For instance, one cannot invoke clone() on a map reference in Java because map specifies no public clone() method. Only map implementations like HashMap and LinkedHashMap have clone() methods, but to carry around the class type of object is not recommended, and it is contrary to the “Program to Interface, not Implementation” principle.
2. The default implementation Object.clone() method returns a Shallow Copy.
In shallow copy, if the field value is a primitive type, it copies its value; otherwise, if the field value is a reference to an object, it copies the reference, hence referring to the same object. Now, if one of these objects is modified, the change is visible in the other. In Deep Copy, in contrast to the shallow copy, the referenced objects are not shared; instead, new objects are created for any referenced objects.
Shallow Cloning

The following program demonstrates using the Object.clone() method by using its default implementation, which returns a shallow copy. We will cover deep copy using the clone() method in the next section.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.Map; // `Subject` needs to implement `Cloneable` too!! class Subject implements Cloneable { private Set<String> subjects; public Subject() { subjects = new HashSet<>( Arrays.asList("Maths", "Science", "English", "History") ); } @Override public Object clone() throws CloneNotSupportedException { // call `super.clone()` to obtain the cloned object reference return super.clone(); } @Override public String toString() { return subjects.toString(); } public Set<String> getSubjects() { return subjects; } } // Note that the `Student` implements `Cloneable` interface class Student implements Cloneable { private String name; // immutable field private int age; // primitive field private Subject subjects; private Map<String, Integer> map; public Student(String name, int age) { this.name = name; this.age = age; map = new HashMap<String, Integer>() {{ put(name, age); }}; subjects = new Subject(); } @Override public String toString() { return Arrays.asList(name, String.valueOf(age), subjects.toString()).toString(); } @Override public Object clone() throws CloneNotSupportedException { // call `super.clone()` to obtain the cloned object reference return super.clone(); } public Set<String> getSubjects() { return subjects.getSubjects(); } public Map<String, Integer> getMap() { return map; } // include remaining getters and setters } // Demonstrate shallow copy of objects using the `clone()` method class Main { // Utility method to compare two objects. It prints shallow copy // if both objects share the same object; otherwise, it prints deep copy public static void compare(Object ob1, Object ob2) { if (ob1 == ob2) { System.out.println("Shallow Copy"); } else { System.out.println("Deep Copy"); } }; public static void main(String[] args) { Student student = new Student("Jon Snow", 22); Student clone = null; try { clone = (Student) student.clone(); System.out.println("Cloned Object: " + clone + '\n'); } catch (CloneNotSupportedException ex) { ex.printStackTrace(); } compare(student.getSubjects(), clone.getSubjects()); compare(student.getMap(), clone.getMap()); // any change made to the clone's map will reflect on the student's map clone.getMap().put("John Cena", 40); System.out.println(student.getMap()); } } |
Output:
Cloned Object: [Jon Snow, 22, [Maths, English, Science, History]]
Shallow Copy
Shallow Copy
{Jon Snow=22, John Cena=40}
Deep Cloning
If a class contains only primitives and Immutable fields, a shallow copy works fine. But any mutable fields such as collections and arrays would be shared between the original and the copy since Object.clone() returns an exact copy of the original object.
For deep cloning, if a class contains any object references, then the clone() method should perform any required modifications on the object received from the superclass before returning to the caller. i.e., clone() method must modify mutable fields of objects returned by super.clone(). One way of doing it is to call the clone() method on mutable fields.

If we try to assign values to final fields within a clone() method, it will result in a compilation error. The field’s value is an immutable object, we can just let it copy the reference, and both the original and its clone will share the same object. But for mutable objects, it must be deeply copied.
Serialization and deserialization is another alternative to using a clone which handles final data members correctly, as shown in the next section. We can also make use of Copy Constructor that takes an instance of the same class as the object and copies all the primitive fields, and create new objects for any referenced objects to that new instance.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Set; import java.util.Map; // `Subject` needs to implement `Cloneable` too!! class Subject implements Cloneable { private Set<String> subjects; public Subject() { subjects = new HashSet<>( Arrays.asList("Maths", "Science", "English", "History") ); } @Override public Subject clone() throws CloneNotSupportedException { Subject obj = (Subject)super.clone(); obj.subjects = new HashSet<>(this.subjects); return obj; } @Override public String toString() { return subjects.toString(); } public Set<String> getSubjects() { return subjects; } } // Note that the `Student` implements `Cloneable` interface class Student implements Cloneable { private String name; // immutable field private int age; // primitive field private Subject subjects; private Map<String, Integer> map; public Student(String name, int age) { this.name = name; this.age = age; map = new HashMap<String, Integer>() {{ put(name, age); }}; subjects = new Subject(); } @Override public String toString() { return Arrays.asList(name, String.valueOf(age), subjects.toString()).toString(); } @Override public Object clone() throws CloneNotSupportedException { Student student = (Student) super.clone(); // primitive fields like int are not copied, as their content // is already copied // String is immutable // call `clone()` on `Subject` object student.subjects = this.subjects.clone(); // create a new instance of `Hashmap` student.map = new HashMap<>(this.map); return student; } public Set<String> getSubjects() { return subjects.getSubjects(); } public Map<String, Integer> getMap() { return map; } // include remaining getters and setters } // Demonstrate a deep copy of objects using the `clone()` method class Main { // Utility method to compare two objects. It prints shallow copy // if both objects share the same object; otherwise, it prints deep copy public static void compare(Object ob1, Object ob2) { if (ob1 == ob2) { System.out.println("Shallow Copy"); } else { System.out.println("Deep Copy"); } }; public static void main(String[] args) { Student student = new Student("Jon Snow", 22); Student clone = null; try { clone = (Student) student.clone(); System.out.println("Cloned Object: " + clone + '\n'); } catch (CloneNotSupportedException ex) { ex.printStackTrace(); } compare(student.getSubjects(), clone.getSubjects()); compare(student.getMap(), clone.getMap()); // any change made to the clone's map will not reflect on the student's map clone.getMap().put("John Cena", 40); System.out.println(student.getMap()); } } |
Output:
Cloned Object: [Jon Snow, 22, [Maths, English, Science, History]]
Deep Copy
Deep Copy
{Jon Snow=22}
The Custom clone() method is tedious to implement, error-prone, and difficult to maintain. The code must be modified every time any change is made to the class fields.
2. Deep Cloning: Apache SerializationUtils.clone() method
The JDK provides no deep-copy equivalent to Object.clone() method. But we can refer implementation of clone() method provided by Apache Commons Lang SerializationUtils class. The prototype of the SerializationUtils.clone() is:
|
1 |
public static Object clone(Serializable object); |
It basically performs deep cloning using serialization. It is beneficial as deep cloning using the Object’s clone method is very painful and error-prone for complex object graphs.
Cons:
- This is many times slower than manually cloning on all objects in your object instance.
- If this method is used, all the objects involved must be Serializable, i.e., objects must implement Serializable interface; otherwise, it will throw a
java.io.NotSerializableException.
The following program demonstrates it:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
import org.apache.commons.lang3.SerializationUtils; import java.io.Serializable; import java.util.*; // `Subject` needs to implement the `Serializable` interface too!! class Subject implements Serializable { private Set<String> subjects; public Subject() { subjects = new HashSet<>( Arrays.asList("Maths", "Science", "English", "History") ); } @Override public String toString() { return subjects.toString(); } public Set<String> getSubjects() { return subjects; } } // Note that the `Student` implements `Serializable` interface class Student implements Serializable { private String name; // immutable field private int age; // primitive field private Subject subjects; private Map<String, Integer> map; public Student(String name, int age) { this.name = name; this.age = age; map = new HashMap<String, Integer>() {{ put(name, age); }}; subjects = new Subject(); } @Override public String toString() { return Arrays.asList(name, String.valueOf(age), subjects.toString()).toString(); } public Set<String> getSubjects() { return subjects.getSubjects(); } public Map<String, Integer> getMap() { return map; } // include remaining getters and setters } // Demonstrate deep copy of objects using `clone()` method provided by // Apache Common's `SerializationUtils` class Main { // Utility method to compare two objects. It prints shallow copy // if both objects share the same object; otherwise, it prints deep copy public static void compare(Object ob1, Object ob2) { if (ob1 == ob2) { System.out.println("Shallow Copy"); } else { System.out.println("Deep Copy"); } }; public static void main(String[] args) { Student student = new Student("Jon Snow", 22); // call SerializationUtils's `clone()` method Student clone = (Student) SerializationUtils.clone(student); System.out.println("Cloned Object: " + clone.toString() + '\n'); compare(student.getSubjects(), clone.getSubjects()); compare(student.getMap(), clone.getMap()); // any change made to the clone's map will not reflect on the student's map clone.getMap().put("John Cena", 40); System.out.println(student.getMap()); } } |
Output:
Cloned Object: [Jon Snow, 22, [Jon Snow, 22]]
Deep Copy
Deep Copy
{Jon Snow=22}
That’s all about the clone() method in Java.
References:
https://en.wikipedia.org/wiki/Object_copying#Copying_in_Java
https://en.wikipedia.org/wiki/Clone_(Java_method)
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)