Saturday, June 14, 2008

Cloning of Java objects

Parent class of all objects in java is "Object" which contains several important methos. One of them is "clone" which is used to make a copy of object. There are certain things which you should keep in mind while using clone method of Object.
- implement "Cloneable" interface to each class which you want to clone. If a class does not implement "Cloneable" interface, clone method will throw "CloneableNotSupportedException". This interface does not contain any methods. It is just a marker interface. Suppose you have a Class "Book" of which you want to make a clone, then structure of that class will be:

public class Book implements Cloneable
{
//attributes
//methods
@Override protected Object clone() throws CloneableNotSupportedException
{
//Clone logic
}
}

- Obtain cloned object through super.clone
- if your class only contains primitive attributes or wrappers of primitive attributes or immutable object like String, then you don't need to do anything special inside clone method because clone method automatically makes a copy of primitive data types and immutable objects. Suppose above "Book" class contains following two attributes with accessor methdos for attributes:

private String name;
private Float price;
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Float getPrice() {
return price;
}

public void setPrice(Float price) {
this.price = price;
}

Now to clone Book class you just need to write following implementation in overriding of clone method:

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

- by default clone method makes shallow copy and does not make a Deep copy of object. Deep copy means if your object contains references of other objects or collections, it will not make a copy of those referenced objects and will use same references as was in origianl objects. Suppose above mentioned "Book" class contains an attribute of class "Publisher". Structure of Publisher class is given below:


public class Publisher{
private String pubName;

public String getPubName() {
return pubName;
}

public void setPubName(String pubName) {
this.pubName = pubName;
}
}

Now try out the following code:

Publisher pub = new Publisher();
pub.setPubName("Java Publisher");
orig.setPub(pub);
Logger.getLogger(CloneTest.class.getName()).log(Level.INFO,orig.getPub().getPubName());
Book clone2 = (Book) orig.clone();
Logger.getLogger(CloneTest.class.getName()).log(Level.INFO,clone2.getPub().getPubName());
orig.getPub().setPubName("java Publisher Changed");
Logger.getLogger(CloneTest.class.getName()).log(Level.INFO,clone2.getPub().getPubName());

Output of above code will be:
15-Jun-2008 1:39:47 AM javasolutionsblog.clonetest.CloneTest main
INFO: Java Publisher
15-Jun-2008 1:39:47 AM javasolutionsblog.clonetest.CloneTest main
INFO: Java Publisher
15-Jun-2008 1:39:47 AM javasolutionsblog.clonetest.CloneTest main
INFO: Java Publisher Changed


Although expected output of third log was "Java Publisher" but since clone didn't make copy of refernce object publisher, it used same object in clone as in origignal object, when i make a change in the publisher name in original object, it also reflected in cloned object.

- In order to do deep copy of Book class, we will aso have to implement "Cloneable" interface in "Publisher" class + override clone method in Publisher class too. If Publisher class contains references of other objects, then you will have to implement Cloneable interface + override clone method in each sub class too.
In our case, structure of Publisher class will be:

public class Publisher implements Cloneable{
private String pubName;

public String getPubName() {
return pubName;
}

public void setPubName(String pubName) {
this.pubName = pubName;
}

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

}

Now change the definition of clone method of Book class as follows:

protected Object clone() throws CloneNotSupportedException {
Book clonedBook = (Book) super.clone();
if (this.getPub() != null) {
clonedBook.setPub((Publisher) this.getPub().clone());
}

return clonedBook;
}

4 comments:

Jhulfikar Ali said...

Really a nice piece about Cloning Object in Java. I guess almost you have covered most of the things. Waiting to read more!

Igor Ganapolsky said...

Good point about cloning with deep copies. I wonder - how does it compare to serialization for deep copies? Is it more or less efficient?

Sandeep Bhandari said...

There are alternatives to clone method by which we can achieve the same result as clone and avoid the use Cloneable interface. Basically copy constructors is the option which I normally use to create new copies of my objects.

vikas shukla said...

Very good post admin. Sufficient content is given here to understand every thing. For more information Please visit click here