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
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.
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 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.
Creating Clones with
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
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
age. Now let us create an instance of
Employee and then clone it using
super.clone() as shown next –
Employeeclass has 3 attributes –
EmployeeAddressis a different class containing 3 attributes –
Cloneableinterface. It overrides
Object.clone()method and calls
- Note that if the interface
Cloneableis not implemented then a
CloneNotSupportedExceptionexception is thrown on calling the
- Inside the
CloningInJavawe first create an instance of
EmployeeAddressusing which we create an instance of
- We then create a clone of
empobject by invoking
- We then print
empCloneand find that it contains the same contents as
emp, implying that
empCloneis a clone of
Problem with Shallow Copies
We saw above how to create a clone of an object using
super.clone() method after implementing
Cloneable and overriding
Object.clone() method. We were succesfully able to clone the
emp object to
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
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.
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
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.
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
Employee object created using deep copying would then look like this –
As you can see in the above diagram,
empClone have their own instances of
empAddress. Any change done to
empAddress will not have any affect on
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 –
- Inside the overridden
Employeewe first create a shallow copy of the employee object by using the
super.clone()method, and store this shallo copy in a
- Next a new instance of
empAddressClone, is created using the
cityvalues stored in the
empAddressattribute of the
Employeeobject being cloned(accessed using
empAddressCloneis then set in
empCloneis returned as the cloned object instance.
- In the
empAddress, while cloned
empAddressClone. This is the expected output and matches the diagram for deep copying shown above.
In the above tutorial, we understood what is cloning in Java, saw the main classes and interfaces participating in cloning with an explanation of each of their roles, and then learned how to make shallow copies and deep copies with Java code examples, and their detailed explanation.