Wednesday, February 6, 2013

Clone objects in Java

Java's cloning feature returns field-by-field copy of the object. It creates soft copy of the object on which it gets invoked. Below is the complete signature of the method:
protected native Object clone() throws CloneNotSupportedException
This is a native method and hence it's not implemented in Java (but in C/C++). Above method is present in the root class i.e. Object class and not in Cloneable interface.

 To support cloning of a Java object, you need to do below to the class definition.
  1.  Implement Cloneable interface
  2.  and override clone method (from Object class).
Cloneable interface is a marker interface (it doesn't have any method). The purpose of this interface is to tell JVM that this class is eligible for cloning.

By convention, the returned object should be obtained by calling super.clone. The contract from the specification [JavaSE7] -
for any object x the intent is :

Contract 1 
x.clone() != x   should be true

Contract 2
x.clone().getClass() == x.getClass()  should be true, but these are not absolute requirement

Contract 3
x.clone().equals(x) will be true, but its not an absolute requirement.

The contracts are very loose. Another condition is that no constructor are called to achieve it.

 class Student implements Cloneable {  
      private String name;  
      private int age;  
      public Student(String name, int age) {  
           super();  
           this.name = name;  
           this.age = age;  
      }  
      @Override  
      public String toString() {  
           return "Student [name=" + name + ", age=" + age + "]";  
      }  
      public Student clone() throws CloneNotSupportedException {  
           return (Student) super.clone();  
      }  
      public static void main(String[] args) {  
           Student student = new Student("Siddheshwar", 18);  
           System.out.println("Original Student :" + student);  
           try {  
                Student clonedStudent = student.clone();  
                System.out.println("Clonned Student :" + clonedStudent);  
           } catch (CloneNotSupportedException e) {  
                e.printStackTrace();  
           }  
      }  
 }  

Output:
Original Student :Student [name=Siddheshwar, age=18]

Clonned Student :Student [name=Siddheshwar, age=18]

Point to note about above code :
  1. Cloneable interface does not contain the clone method. So you can't clone an object by just implementing this interface. 
  2. You need to have definition of clone method inside class (which implements Cloneable interface). 
  3. If we try to call the clone() method on an object of a class which doesn't implement the Cloneable interface; you will get runtime exception CloneNotSupportedException.
  4. clone() method is a protected method in Object class so you can't call it directly.
  5. It performs shallow clone/copying
  6. If you implementing the deep clone, the same rule applies. You should call super.clone to acquire the correct type of object and then perform the deep cloning operations.

Significance of super.clone() ?
super.clone() method basically calls Object's clone method. To make sure this works correctly ensure that all the super classes obey this rule. It invokes java.lang.Object clone method to ensure that cloned object is constructed properly.

 Final Note

  1. Class implementing Cloneable interface should provide a properly implemented public clone method.
  2. clone method can return specific class type instead of Object. This is because as of Java SE 1.5, covariant return types are legal. This is why above example returns a Student type instead of Object.
  3. Returning subclass type also saves you from casting in the client code.
Related Post : Shallow Copy vs Deep Copy in Java

No comments:

Post a Comment