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 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 Pattern tutorialClick to Read in-depth tutorial on Prototype Pattern.

Classes involved in cloning in Java

Classes participating when 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.

Cloneable.java: 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? 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.

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 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);
  }
}
 OUTPUT of the above code
Cloned Employee Object:   Employee Name: David   Age: 32   Address: EmployeeAddress { houseNo=’22’,   street= ‘Avenue Street’,   city=’Dallas’ }
Explanation of the code

  • Employee class has 3 attributes – name (of type String), age(Integer) and empAddress(EmployeeAddress).
  • EmployeeAddress is a different class containing 3 attributes – houseNo, street and city.
  • Employee implements Cloneable interface. It overrides Object.clone() method and calls super.clone().
  • Note that if the interface Cloneable is not implemented then a java.lang. CloneNotSupportedException exception is thrown on calling the clone() method on Employee objects.
  • Inside the main() method of CloningInJava we first create an instance of EmployeeAddress using which we create an instance of Employee, named emp.
  • We then create a clone of emp object by invoking emp.clone() which creates empClone object.
  • We then print empClone and find that it contains the same contents as emp, implying that empClone is a clone of emp.

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 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.");
 }
The output of the above code, which also points out the problem with cloning using 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 –

Shallow copying example - cloning in Java

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.

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 –

Deep copying example - cloning in Java

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 copyingEmployee 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;
}
 OUTPUT of the above code
Cloned Employee Object: Employee Name:David Age:32 Address:EmployeeAddress{houseNo=’22’, street=’Avenue Street’, city=’Dallas’}
Explanation of the code

  • Inside the overridden clone() method of Employee we first create a shallow copy of the employee object by using the super.clone() method, and store this shallo copy in a Employee instance named empClone.
  • Next a new instance of EmployeeAddress, named empAddressClone, is created using the houseNo, street and city values stored in the empAddress attribute of the Employee object being cloned(accessed using this keyword).
  • empAddressClone is then set in empClone, and empClone is returned as the cloned object instance.
  • In the CloningInJava class – Employee instance emp contains empAddress, while cloned Employee instance empClone now contains empAddressClone. This is the expected output and matches the diagram for deep copying shown above.

Summary
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.

 

Digiprove sealCopyright © 2014-2016 JavaBrahman.com, all rights reserved.