Cloning in java using clone- Shallow and deep copy - 8 techniques for deep copying- 8 important points about cloning


Contents of page :

  • 8 important  points about cloning in java>
  • Shallow copy
    • Program for shallow copy>
  • Deep copy>
    • Program for deep copy>
  • 8 Different techniques for deep copying>
    • Program for deep copy using Serialization and Deserialization >


Cloning is done for copying the object, cloning can be done using shallow or deep copy, we will discuss it later in post.

8 important points about cloning in java>
  • 1) Definition of clone method -
protected native Object clone() throws CloneNotSupportedException;

  • Clone method is present in java.lang.Object class.
  • Clone is a protected method - clone method can’t be called outside class without inheritance.
  • Clone is native method, if not overridden its implementation is provided by JVM.
  • It returns Object - Means explicitly cast is needed to convert it to original object.
  • Clone is not a keyword in java.

  • 2) By default clone method do shallow copy.

  • 3) Class must implement marker interface java.lang.Cloneable. If class doesn’t implement Cloneable than calling clone method on its object will throw CloneNotSupportedException.

  • 4) shallow copy- If we implement Cloneable interface, we must override clone method and call super.clone() from it, invoking super.clone() will do shallow copy.

  • 5) Deep copy - We need to provide custom implementation of clone method for deep copying.  When the copied object contains some other object its references are copied recursively in deep copy. When you implement deep copy be careful as you might fall for cyclic dependencies

  • 6) Constructor of object is not called when clone method is called.

The precise meaning of "copy" may depend on the class of the object. The general intent is that, for any object x, the expression:
x.clone() != x
will be true, and that the expression:
x.clone().getClass() == x.getClass()
\will be true, but these are not absolute requirements. While it is typically the case that:
x.clone().equals(x)
will be true, this is not an absolute requirement.

  • 8) According to javaDocs  -the returned object should be obtained by calling super.clone. If a class and all of its superclasses (except Object) obey this convention, it will be the case that x.clone().getClass() == x.getClass()



Shallow copy >
Let’s say we want to shallow copy emp object using clone method.
In shallow copy, different object is created after cloning (i.e. clonedEmp is created from emp) but member variables keep on referring to same object (i.e. name and map).
Program for shallow copy>
import java.util.*;
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class CloneShallow implements Cloneable {
   private String name;
   private Map<Integer, Integer> map;
  
   public CloneShallow(String name,Map<Integer,Integer> map){
          this.name=name;
          this.map=map;
   }
  
   /*
   * override clone method for doing shallow copy.
   */
      @Override
   public Object clone() {
          System.out.println("Doing shallow copy");
          try {
                 return super.clone();
          } catch (CloneNotSupportedException e) {
                 return null;
          }
   }
   public static void main(String[] args) throws CloneNotSupportedException  {
         
          Map<Integer,Integer> map=new HashMap<Integer,Integer>();
          map.put(11, 11);
         
          CloneShallow obj=new CloneShallow("ankit",map);
         
          CloneShallow clonedObj=(CloneShallow)obj.clone();
         
          System.out.println(obj==clonedObj);             //false
          System.out.println(obj.name==clonedObj.name);   //true
          System.out.println(obj.map==clonedObj.map);     //true
         
         
   }
}
/*OUTPUT
Doing shallow copy
false
true
true
*/


Deep copy >
Let’s say we want to deep copy emp object using clone method.
In deep copy, different object is created after cloning (i.e. clonedEmp is created from emp) , also member variables starts referring to different objects (i.e. name and map).

Program for deep copy>
package clone;
import java.util.*;
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class CloneDeep implements Cloneable {
   public CloneDeep(String name,Map<Integer,Integer> map){
          this.name=name;
          this.map=map;
   }
  
   private String name;
   private Map<Integer,Integer> map;
  
   /*
   * override clone method for doing deep copy.
   */
      @Override
   public CloneDeep clone(){
          System.out.println("Doing deep copy");
         
          Map<Integer,Integer> map=new HashMap<Integer,Integer>();
          Iterator<Integer> it=this.map.keySet().iterator();
          while(it.hasNext()){
                 Integer key=it.next();
                 map.put(key,this.map.get(key) );
          }
         
          CloneDeep cloneDetailedDeep=new CloneDeep(new String(name), map);
         
          return cloneDetailedDeep;
   }
   public static void main(String[] args) throws CloneNotSupportedException  {
         
         
          Map<Integer,Integer> map=new HashMap<Integer,Integer>();
          map.put(1, 11);
         
          CloneDeep obj1=new CloneDeep("sam",map);
         
          CloneDeep obj2=(CloneDeep)obj1.clone();
         
          System.out.println(obj1==obj2);           //false
          System.out.println(obj1.name==obj2.name); //false
          System.out.println(obj1.map==obj2.map);   //false
                      
         
         
   }
}
/*OUTPUT
Doing deep copy
false
false
false
*/



8 Different techniques for deep copying>

  • 1) XStream can be used for cloning.
private static final XStream XSTREAM = new XStream();
//code
Object clonedObject = XSTREAM.fromXML(XSTREAM.toXML(obj));



  • 3) Kyro for deep cloning.

  • 4) Cloner can be used for cloning which performs relatively fast cloning with reflection ( faster than serialization methods).
Cloner cloner=new Cloner();
MyClass clone=cloner.deepClone(obj);




Let's say emp is reference variable referring to object of Employee class.
Employee empClone = org.apache.commons.lang.SerializationUtils.clone(emp);
empClone will refer to cloned object.



  • 6) Dozer - Dozer for deep cloning.
Dozer is a Java Bean to Java Bean mapper that recursively copies data from one object to another, it is an open source mapping framework that is robust, generic, flexible, reusable, and configurable.

  • 7) Deep cloning using Serialization and deserialization - Simply serialize object by creating object of ObjectOutputStream and then using its writeObject method. And then deserializing the object. (As done in above program)

  • 8) Deep cloning using Reflection - (As done in above program)


Program for deep copy using Serialization and Deserialization >
Let’s say we want to deep copy emp object using serialization.
In serialization and deserialization process, different object is created after deserialization ( i.e. deSerializedEmp is created from emp) , also member variables starts referring to different objects (i.e. name and map).

package clone;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
class Employee implements Serializable  {
  
   private static final long serialVersionUID = 1L;
   private String name;
   private Map<Integer,Integer> map;
  
   public Employee(String name,Map<Integer,Integer> map) {
          this.name = name;
          this.map=map;
   }
   @Override
   public String toString() {
          return "Employee [name=" + name + "]";
   }
   public String getName() {
          return name;
   }
   public Map<Integer, Integer> getMap() {
          return map;
   }
}
/**
* Author : AnkitMittal  Copyright (c)- javaMadeSoEasy.com
* Main class
*/
public class CloneUsingSerialization {
   public static void main(String[] args) {
          Map<Integer,Integer> map=new HashMap<Integer,Integer>();
          map.put(1, 11);
         
          Employee emp = new Employee("ankit",map);
          try {
                 OutputStream fout = new FileOutputStream("ser.txt");
                 ObjectOutput oout = new ObjectOutputStream(fout);
                 System.out.println("Serialization process has started, "
                                                          + "serializing employee object...");
                 oout.writeObject(emp);
                 fout.close();
              oout.close();
                 System.out.println("employee Serialization completed.");
                
                 //DeSerialization process >
                
                
                 InputStream fin=new FileInputStream("ser.txt");
                 ObjectInput oin=new ObjectInputStream(fin);
                 System.out.println("\nDeSerialization process has started, "
                                                          + "deSerializing employee object...");
                 Employee deSerializedEmp=(Employee)oin.readObject();
                 fin.close();
             oin.close();
                 System.out.println("employee DeSerialization completed.");
                
                 System.out.println(emp==deSerializedEmp);                     //false
                 System.out.println(emp.getName()==deSerializedEmp.getName()); //false
                 System.out.println(emp.getMap()==deSerializedEmp.getMap()); //false
                
          } catch (IOException | ClassNotFoundException  e) {
                 e.printStackTrace();
          }
   }
}
/*OUTPUT
Serialization process has started, serializing employee objects...
Object Serialization completed.
DeSerialization process has started, displaying employee objects...
Object DeSerialization completed.
false
false
false
*/


For more : Deep copy in java using Serialization and Deserialization


RELATED LINK>

Labels: Core Java
eEdit
Must read for you :