Cloning in Java | Shallow Copy and Deep Copy tutorial with examples
Introduction
This tutorial covers all aspects related to cloning in Java. It starts off with defining cloning, which is followed by understanding the classes and methods using which cloning is accomplished. We will then take up a real example of cloning wherein we will create a shallow copy using
Creating clones of objects rather than instantiating and populating objects from scratch everytime is a design decision. Prototype pattern, from the Gang of Four Pattern Design Patterns set, looks at the motivations and scenarios where cloning can be applied. If you are interesting in learning the design aspects regarding when-to-clone then you can refer the Prototype Design PatternClick to Read in-depth tutorial on Prototype Pattern tutorial. Classes involved in cloning in Java
To clone a class's object in Java, 3 actors(2 classes and 1 interface) need to work together. Let us understand the role played by each.
Object.java:
Cloneable.java:
ClassToClone.java:
Creating Clones with
Let us now see the
OUTPUT of the above code
Explanation of the code
The output of the above code, which also points out the problem with cloning using
What has happened while cloning
As you can see in the above diagram, while
This requirement of ours, of having completely independent/separate object clones, brings us to our next topic - Deep Copying.
Deep Copying
Deep copying clones not just the 'shallow' primitive values, it also creates copies of the nested object hirerarchy inside the object being cloned. A clone of an
As you can see in the above diagram,
OUTPUT of the above code
Explanation of the code
super.clone()
method. Next, we will look at the inherent disadvantage of shallow copies, which will be followed by understanding the concept of deep copying by extending the shallow copying example code to create deep copies of the cloned object.
What is Cloning
Cloning an object refers to creating a copy of the object. Given an object, if you want to create multiple objects which are 'exact' copies of that object, but do not want to go through the process of defining a new object instance, then cloning is what you will do.Creating clones of objects rather than instantiating and populating objects from scratch everytime is a design decision. Prototype pattern, from the Gang of Four Pattern Design Patterns set, looks at the motivations and scenarios where cloning can be applied. If you are interesting in learning the design aspects regarding when-to-clone then you can refer the Prototype Design PatternClick to Read in-depth tutorial on Prototype Pattern tutorial. Classes involved in cloning in Java
To clone a class's object in Java, 3 actors(2 classes and 1 interface) need to work together. Let us understand the role played by each.
Object.java:
java.lang.Object
is the parent of all classes in Java. The reason why it plays a part in cloning is because the actual cloning logic is written in an overriden method clone() which is originally defined in Object class.java.lang.Cloneable
is a marker interface (to understand what is a marker interface see the knowledge nugget below). Any class which intends to provide the capability of it's objects getting cloned needs to implement the Cloneable interface.ClassToClone.java:
ClassToClone
is the class whose objects we plan to clone. ClassToClone has to implement Cloneable, and it has to override Object's clone() method with the overriding logic, in order to facilitate cloning of its objects.
What is a marker interface?
A marker interface is an empty interface i.e. it doesn't contain any methods. Its purpose is to indicate to the Java runtime regarding a specific role which will be played by any class implementing it. Examples of commonly used marker interfaces include
Serializable
, Cloneable
etc.
super.clone()
, i.e Creating Shallow Copies
One of the most common and straightforward way of creating clones is by invoking super.clone()
from inside the overriden clone()
method of the class you are trying to clone. This directly invokes the Object
’s clone()
method and clones the object's content into a new object.Let us now see the
super.clone()
method in action to understand its working. Let us take a class Employee
with 2 attributes name
and age
. Now let us create an instance of Employee
and then clone it using super.clone()
as shown next - Java code for cloning an object using super.clone() / shallow copying
//Employee.java
package com.javabrahman.corejava;
public class Employee implements Cloneable{
private String name;
private Integer age;
private EmployeeAddress empAddress;
//Employee constructor
public Employee(String name, Integer age, EmployeeAddress empAddress) {
this.name = name;
this.age = age;
this.empAddress = empAddress;
}
//setters and getters for name, age and empAddress go here
public String toString(){
return "Employee Name:"+this.name
+" Age:"+this.age
+" Address:"+empAddress;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Employee)) {
return false;
}
Employee empObj = (Employee) obj;
return this.age == empObj.age
&& this.name.equalsIgnoreCase(empObj.name);
}
@Override
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
//EmployeeAddress.java
package com.javabrahman.corejava;
public class EmployeeAddress {
private String houseNo;
private String street;
private String city;
//EmployeeAddress constructor
public EmployeeAddress(String houseNo, String street, String city) {
this.houseNo = houseNo;
this.street = street;
this.city = city;
}
//setters and getters for houseNo, street and city go here
@Override
public String toString() {
return "EmployeeAddress{" +
"houseNo='" + houseNo + '\'' +
", street='" + street + '\'' +
", city='" + city + '\'' +
'}';
}
}
//CloningInJava.java
package com.javabrahman.corejava;
public class CloningInJava {
public static void main(String args[]){
EmployeeAddress empAddress=new EmployeeAddress("22","Avenue Street", "Dallas");
Employee emp=new Employee("David", 32,empAddress);
Employee empClone=null;
try {
empClone=(Employee) emp.clone();
}catch(CloneNotSupportedException cnse){
cnse.printStackTrace();
}
System.out.println("Cloned Employee Object: "+empClone);
}
}
Cloned Employee Object: Employee Name: David Age: 32 Address: EmployeeAddress { houseNo='22', street= 'Avenue Street', city='Dallas' }
Employee
class has 3 attributes -name
(of typeString
),age
(Integer
) andempAddress
(EmployeeAddress
).EmployeeAddress
is a different class containing 3 attributes -houseNo
,street
andcity
.Employee
implementsCloneable
interface. It overridesObject.clone()
method and callssuper.clone()
.- Note that if the interface
Cloneable
is not implemented then ajava.lang.
CloneNotSupportedException
exception is thrown on calling theclone()
method onEmployee
objects. - Inside the
main()
method ofCloningInJava
we first create an instance ofEmployeeAddress
using which we create an instance ofEmployee
, namedemp
. - We then create a clone of
emp
object by invokingemp.clone()
which createsempClone
object. - We then print
empClone
and find that it contains the same contents asemp
, implying thatempClone
is a clone ofemp
.
super.clone()
method after implementing Cloneable
and overriding Object.clone()
method. We were succesfully able to clone the emp
object to empClone
.
However, there is a problem with the cloning done above. To understand the problem, let us add the following code to the end of main()
method of CloningInJava
class, i.e. after we clone emp
object. if (empClone.getEmpAddress() == emp.getEmpAddress() ) {
System.out.println("empClone's empAddress reference equals emp's empAddress reference.");
}
super.clone()
, is as follows - empClone's empAddress reference equals emp's empAddress reference. What has happened while cloning
emp
object and creating empClone
object is depicted in the diagram below - As you can see in the above diagram, while
empClone
creates a copy of the primitive attributes, i.e. name
and age
, it conveniently "re-uses" the same empAddress
object for empClone
. This is what is known as a Shallow Copy i.e. a copy/clone in which the primitive values are cloned but the object references still point to the references of the original object.
Drawback of Shallow Copying
Shallow Copies have a significant drawback. As we saw above, after cloning emp
and empClone
point to the same empAddress
object reference. If after cloning we decide to change the address for empClone
, then the same address change will also reflect in the original emp
object. This is an unwanted behaviour/side effect, as what we really want and two separate clones of Employee class with their entire object hierarchies cloned.This requirement of ours, of having completely independent/separate object clones, brings us to our next topic - Deep Copying.
Employee
object created using deep copying would then look like this - As you can see in the above diagram,
emp
and empClone
have their own instances of empAddress
. Any change done to emp
’s empAddress
will not have any affect on empClone
’s empAddress
and vice-a-versa.
To implement deep copying - Employee
will still need to implement Cloneable
, and it will still override Object.clone()
method. But inside the overridden clone()
method, instead of calling super.clone()
, a clone of an Employee
object is constructed step-by-step using custom code as shown in the code below -Java code for deep copying
//Code for CloningInJava.java, Employee.java and EmployeeAddress.java remain the same
//Only the code in Employee.clone() method changes to implement deep copying
@Override
public Object clone() throws CloneNotSupportedException {
Employee empClone = (Employee) super.clone();
EmployeeAddress empAddressClone = new EmployeeAddress(this.empAddress.getHouseNo(),
this.empAddress.getStreet(),
this.empAddress.getCity());
empClone.setEmpAddress(empAddressClone);
return empClone;
}
Cloned Employee Object: Employee Name:David Age:32 Address:EmployeeAddress{houseNo='22', street='Avenue Street', city='Dallas'}
- Inside the overridden
clone()
method ofEmployee
we first create a shallow copy of the employee object by using thesuper.clone()
method, and store this shallo copy in aEmployee
instance namedempClone
. - Next a new instance of
EmployeeAddress
, namedempAddressClone
, is created using thehouseNo
,street
andcity
values stored in theempAddress
attribute of theEmployee
object being cloned(accessed usingthis
keyword). empAddressClone
is then set inempClone
, andempClone
is returned as the cloned object instance.- In the
CloningInJava
class -Employee
instanceemp
containsempAddress
, while clonedEmployee
instanceempClone
now containsempAddressClone
. This is the expected output and matches the diagram for deep copying shown above.