Mainak is an experienced Technology Consultant specializing in JEE, Web Development and Open source technologies. He is currently based out of United Kingdom. He is die hard technology enthusiast trying to explore the latest in the world of technology. In past time he loves blogging on his website: http://idiotechie.com. Mainak is a DZone MVB and is not an employee of DZone and has posted 11 posts at DZone. You can read more from them at their website. View Full User Profile

Deep Diving into Cloning

11.08.2012
| 3267 views |
  • submit to reddit

 

Before we proceed with the cloning concept let’s refresh our basics with the object creation concept. When the objects are created using the new operator the objects gets the memory allocation in the Heap.

Object Creation in Heap

Object Creation in Heap

In Java ideally objects are modified through reference variable only i.e. only the memory address of the object is copied and hence any changes in the original object will be reflected in the new variable.

Glass objGlass1=new Glass();

Glass objGlass2=objGlass1;

Here, in this case any changes you make to object objGlass1 will reflect in object objGlass2 and vice versa. That means ‘objGlass1== objGlass2‘ will return true both the reference variables objGlass1 and objGlass2 are referring to the same object. However if you are intending to copy the object unlike just copying the reference of the object then you will need cloning.

What is cloning?

Cloning is a process of copying an object i.e. creating a new instance by copying itself. Cloning in Java can be done by use of clone() method of the object.

Cloning creates and returns a copy of the object, with the same class and with all the fields having the same values.

Glass objGlass1 = new Glass();

Glass objGlass2 = (Glass) objGlass.clone();

Let’s see the below analysis after cloning:

  • objGlass1!=objGlass2  returns TRUE which means that objGlass1 and objGlass2  are referring to two different memory locations i.e. two different objects.
  • objGlass1.getClass()==objGlass2 .getClass() returns TRUE which means the cloned object and the original object should be of the same type.
  • objGlass1.equals(objGlass2) returns TRUE which means the cloned object data should be equal to the original one(However it can be changed any time after cloning).

Shallow Cloning vs Deep Cloning

Java supports two types of Cloning – Shallow Cloning and Deep Cloning.

In case of Shallow cloning a new object is created that has an exact copy of the values in the original object. The clone() method  of the Object provides the Shallow cloning. In this cloning mechanism the object is copied without its contained objects.

Shallow clone only copies the top level structure of the object not the lower levels.

Structure:

Shallow Cloning Structure

Shallow Cloning Structure

In the above diagram the OriginalObject1 has Field1 and a object contained called ReferenceObject1. Now during Shallow cloning of OriginalObject1 the ClonedObject2 is created with Field2 having the copied value from Field1 and it still points to the ReferenceObject1. The reason behind this is the Field1 is of primitive type so its values are copied into a Field2. However since ReferenceObject1 is an Object type the ClonedObject2 points to the same ReferenceObject1.

Any changes made to ReferenceObject1 will be visible ClonedObject2.

Shallow Cloning Structure

Shallow Cloning Structure

In case of Deep Cloning all the fields are copied. In this case even the objects referenced are copied in the cloned object along with the fields.

Deep Cloning Structure

Deep Cloning Structure

As mentioned in the above figure the OriginalObject1 has a primitive type Field1 and a ReferenceObject1. Now when we do a deep cloning of the OriginalObject1 then the ClonedObject2 is created along with Field2 is having the copied values from Field1 and ReferenceObject2 containing the copied values of ReferenceObject1.

Deep Cloning Structure

Deep Cloning Structure

Example of Shallow Cloning:

Shallow Cloning Example

Shallow Cloning Example

Shallow Cloning Example

In the above example we have an original object Employee which has reference to Department class and a field EmployeeName. At the first instance let’s assume that the values of the EmployeeName= “Chris” and DepartmentName =”Sales”. When we clone the object Employee through Shallow Cloning then a ClonedEmployee object is created which has a duplicate field cloned EmployeeName and a Department. However we need to note that there is no duplicate Department object created. The cloned Employee object refers the same memory address of the referenced class Department.

So now when we change the original object values of EmployeeName to “Peter” and DepartmentName to “Finance” then the cloned EmployeeName field does not change. It still contains the old value (as per the above section of the diagram). However we must notice that the cloned DepartmentName has been modified now to “Finance” to reflect the change. This is because the cloned Employee refers to the same memory address as of the original object. So any change made to the original object reference is also visible to the cloned object referencing the original object. It doesn’t get duplicated like the fields.

Code Example for Shallow Cloning

Department.java(ReferenceObject)

Code:
public class Department {
    private String deptName;
 
    public Department(String str) {
        deptName = str;
    }
 
    public String getDeptName() {
        return deptName;
    }
 
    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }
}

Employee.java (main object)

public class Employee implements Cloneable {
    private String employeeName;
    private Department dept;
 
    public String getEmployeeName() {
        return employeeName;
    }
 
    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }
 
    public Department getDept() {
        return dept;
    }
 
    public void setDept(Department dept) {
        this.dept = dept;
    }
 
    public Employee(String emp, String empDept) {
        employeeName = emp;
        dept = new Department(empDept);
    }
 
    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

Client.java

public static void main(String[] args) {
        Employee emp = new Employee("Chris", "Sales");
        System.out.println("Original Object value - Employee Name:"
                + emp.getEmployeeName() + " & department name:"
                + emp.getDept().getDeptName());
        Employee clonedEmployee = (Employee) emp.clone();
        System.out.println("Cloned object value - Employee Name:"
                + clonedEmployee.getEmployeeName() + " & department name:"
                + clonedEmployee.getDept().getDeptName());
        // Now let's change values of Original Object
        emp.setEmployeeName("Peter");
        emp.getDept().setDeptName("Finance");
        System.out
        .println("Original Object value after it is modified - Employee Name:"
                + emp.getEmployeeName()
                + " & department name:"
                + emp.getDept().getDeptName());
        System.out
        .println("Cloned object value after modification of original object" +
                " - Employee Name:"
                + clonedEmployee.getEmployeeName()
                + " & department name:"
                + clonedEmployee.getDept().getDeptName());
    }


Deep Cloning Example

Deep Cloning Example

Deep Cloning Example

In case of Deep cloning unlike the Shallow cloning the all the fields of the original object is copied to the clone object including the object which was referenced by the original object. This process make a copy of the dynamically allocated memory pointed to by the fields.

In the above example even if the original object is modified and its values are changed then the cloned object is not changed including the reference object value since it does not refer to the same memory address.

Code Example for Deep Cloning:

In case of deep cloning the only change happens in the clone() method. Unlike Shallow cloning the super.clone() method is not called and instead an object is created using the new operator inside the clone() method.

public Object clone() {
    //Deep Copy process
        Employee e = new Employee(employeeName, dept.getDeptName());
        return e;
}

Hope you have enjoyed this article. Please feel free to provide your feedback and comments.
Previous Page

Download Complete Code:
Download Sample Code

Published at DZone with permission of Mainak Goswami, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Tyler Van Gorder replied on Fri, 2012/11/09 - 11:50am

An alternate strategy for deep cloning/copying :

I have found that many times having "clone" do a deep copy can be error prone. Developers may add new instance variables to a class and forget to also modify their clone method. The result is that you end up having a "partial" deep copy and worse this type of error is "silent" and typically manifests itself in strange ways. 

A solution to this problem that has worked out well for us is to make the object you are "cloning" implement the Serializable interface. To make a deep copy of your object, you can use serialization to write your object to a byte stream and then read that stream back in to a new instance of your object. Serialization is recursive, makes new copies of each object and will fail  fast if one of the member variables is not serializable. There is a small performance penalty for  using this approach and you have to weigh the safety of such an approach against the performance.

The following method will make a deep copy of any object that implements serializable: 

	public static <T> T deepCopy(T pSourceObject) {

		ObjectOutputStream lOutStream = null;
		ObjectInputStream lInStream = null;
		try {
			ByteArrayOutputStream lByteStream = new ByteArrayOutputStream();
			lOutStream = new ObjectOutputStream(lByteStream);
			lOutStream.writeObject(pSourceObject);
			ByteArrayInputStream lByteInStream = new ByteArrayInputStream(
			   lByteStream.toByteArray());
			lInStream = new ObjectInputStream(lByteInStream);
			return (T) lInStream.readObject();
		} finally {
				lOutStream.close();
				lInStream.close();
		}
	}

view sourceprint 

Thanks for the article.


Mainak Goswami replied on Sat, 2012/11/10 - 4:31am in response to: Tyler Van Gorder

Thanks Tyler. This is definitely a useful strategy. Thanks for sharing.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.