Object Cloning in Java

A clone is an exact copy of the original. In java, it essentially means the ability to create an object with similar state as the original object.


By default, java cloning is ‘field by field copy’
i.e. as the Object class does not have idea about the structure of class on which clone() method will be invoked. So, JVM when called for cloning, do following things:

1) If the class has only primitive data type members then a completely new copy of the object will be created and the reference to the new object copy will be returned.

2) If the class contains members of any class type then only the object references to those members are copied and hence the member references in both the original object as well as the cloned object refer to the same object.

 

How to clone in Java??
A) You must implement Cloneable interface.
B) You must override clone() method from Object class. [Its weird. clone() method should have been in Cloneable interface.]

public class Employee implements Cloneable{

    private int empoyeeId;
    private String employeeName;
    private Department department;

    public Employee(int id, String name, Department dept)
    {
        this.empoyeeId = id;
        this.employeeName = name;
        this.department = dept;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    //Accessor/mutators methods will go there
}

// Department class
public class Department
{
    private int id;
    private String name;
 
    public Department(int id, String name)
    {
        this.id = id;
        this.name = name;
    }
    //Accessor/mutators methods will go there
}


public class TestCloning {
 
    public static void main(String[] args) throws CloneNotSupportedException
    {
        Department dept = new Department(1, "Human Resource");
        Employee original = new Employee(1, "Admin", dept);
        //Lets create a clone of original object
        Employee cloned = (Employee) original.clone();
        //Let verify using employee id, if cloning actually workded
        System.out.println(cloned.getEmpoyeeId());
 
        //Verify JDK's rules
 
        //Must be true and objects must have different memory addresses
        System.out.println(original != cloned);
 
        //As we are returning same class; so it should be true
        System.out.println(original.getClass() == cloned.getClass());
 
        //Default equals method checks for refernces so it should be false. If we want to make it true,
        //we need to override equals method in Employee class.
        System.out.println(original.equals(cloned));
    }
}
Output:
1
true
true
false



public class TestCloning { 
    public static void main(String[] args) throws CloneNotSupportedException {
        Department hr = new Department(1, "Human Resource");
        Employee original = new Employee(1, "Admin", hr);
        Employee cloned = (Employee) original.clone();
 
        //Let change the department name in cloned object and we will verify in original object
        cloned.getDepartment().setName("Finance");
 
        System.out.println(original.getDepartment().getName());
    }
}
Output: Finance


 

Shallow Cloning

This is default implementation in java. In overridden clone method, if you are not cloning all the object types (not primitives), then you are making a shallow copy.

All above examples are of shallow copy only, because we have not cloned the Department object on Employee class’s clone method.

 

Deep cloning

It is the desired behavior in most the cases. We want a clone which is independent of original and making changes in clone should not affect original.

//Modified clone() method in Employee class
@Override
protected Object clone() throws CloneNotSupportedException {
    Employee cloned = (Employee)super.clone();
    cloned.setDepartment((Department)cloned.getDepartment().clone());
    return cloned;
}

I modified the Employee classes clone() method and added following clone method in Department class.
//Defined clone method in Department class.
@Override
protected Object clone() throws CloneNotSupportedException {
    return super.clone();
}

Now testing our cloning code gives desired result and name of department will not be modified.
public class TestCloning {
    public static void main(String[] args) throws CloneNotSupportedException {
        Department hr = new Department(1, "Human Resource");
        Employee original = new Employee(1, "Admin", hr);
        Employee cloned = (Employee) original.clone();
 
        //Let change the department name in cloned object and we will verify in original object
        cloned.getDepartment().setName("Finance");
 
        System.out.println(original.getDepartment().getName());
    }
}
Output:
Human Resource

 

So deep cloning requires satisfaction of following rules.

*  No need to separately copy primitives.
*  All the member classes in original class should support cloning and in clone method of  original class in context should call super.clone() on all member classes.
*  If any member class does not support cloning then in clone method, one must create a new instance of that member class and copy all its attributes one by one to new member class object. This new member class object will be set in cloned object.

 

 

Using copy constructors

Copy constructors are special constructors in a class which takes argument for its own class type. So, when you pass an instance of class to copy constructor, then constructor will return a new instance of class with values copied from argument instance. Lets see this in example:

public class PointOne {
    private Integer x;
    private Integer y;
 
    public PointOne(PointOne point){
        this.x = point.x;
        this.y = point.y;
    }
}

This method looks simple and it is until comes inheritance. When you define a class by extending above class, you need to define a similar constructor there also. In child class, you need to copy child specific attributes and pass the argument to super class’s constructor. Lets see how?

public class PointTwo extends PointOne{
    private Integer z;
 
    public PointTwo(PointTwo point){
        super(point); //Call Super class constructor here
        this.z = point.z;
    }
}

So, are we fine now? NO. The problem with inheritance is that exact behavior is identified only in run time. So, in our case if some class passed the instance of PointTwo in constructor of PointOne. In this case, you will get the instance of PointOne in return where you passed instance of PointTwo as argument. Lets see this in code:

class Test
{
    public static void main(String[] args)
    {
        PointOne one = new PointOne(1,2);
        PointTwo two = new PointTwo(1,2,3);
 
        PointOne clone1 = new PointOne(one);
        PointOne clone2 = new PointOne(two);
 
        //Let check for class types
        System.out.println(clone1.getClass());
        System.out.println(clone2.getClass());
    }
}
Output:
class corejava.cloning.PointOne
class corejava.cloning.PointOne

 
Links: http://mrbool.com/how-to-implement-cloning-in-java-using-cloneable-interface/28410,
http://stackoverflow.com/questions/4081858/about-java-cloneable, http://www.artima.com/intv/bloch13.html,
http://coderevisited.com/cloneable-interface-in-java/,

Good article on object cloning in java: http://howtodoinjava.com/core-java/cloning/a-guide-to-object-cloning-in-java/

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s