Friday, June 10, 2011

Java : Cloning

Cloning is a concept that creates copy from existing object.

We have two types of copying process. Those are Shallow Copy and Deep Copy.

In Java, We have clone method in Object class and it creates shallow copy of an object but for this class must implement the Cloneable interface.

Example :

public class Sample implements Cloneable{
  private int i = 0;
 
 public int getI(){
    return i;
 }
 public void setI(int i){
  this.i = i;
 }

 public Object clone() throws CloneNotSupportedException{
   return super.clone();
 }
}

Here, we need to override clone method because clone method is protected so it is not visible from other classes.

Shallow Copy: Using this concept, we will copy the properties of class so only primitive values are cloned. It will be implemented using clone method.

Deep Copy: Using this concept, we will set the properties of class into objects so primitive and non-primitive values are cloned. For this, we need to implement clone method for this.

Note : While implementing Singleton Pattern, We need to override clone method to stop creating new object. So clone method will be like

public Object clone() throws CloneNotSupportedException {
       throw new CloneNotSupportedException();
}


Cloning Implemenation :
For convinience purpose, I have implemented serializable interface to implement Unoptimized deep copy.

Class Deep :
package com.lenin.clone;
import java.io.Serializable;

public class Deep implements Coneable, Serializable {
private static final long serialVersionUID = 2531923642926537348L;
private String one = null;
/**
* @return the one
*/
public String getOne() {
return one;
}
/**
* @param one the one to set
*/
public void setOne(String one) {
this.one = one;
}
}

Class Shallow :


package com.lenin.clone;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Shallow implements Cloneable, Serializable {
private static final long serialVersionUID = -3385874500154579605L;
private String two = null;
private Deep a = null;
/**
* @return the two
*/
public String getTwo() {
return two;
}
/**
* @param two the two to set
*/
public void setTwo(String two) {
this.two = two;
}
/**
* @return B
* @throws CloneNotSupportedException
*/
@Override
protected Shallow clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return (Shallow) super.clone();
}
/**
* @return the a
*/
public Deep getA() {
return a;
}
/**
* @param a the a to set
*/
public void setA(Deep a) {
this.a = a;
}
/**
* Shallow copy will create new instance for object and copy the properties to new object.
* @param b1
* @return b2
*/
public Shallow shallowCopy(){
Shallow b = new Shallow();
b.setA(this.getA());
b.setTwo(this.getTwo());
return b;
}
/**
* Deep copy will cretate new instances for object and it contents recurrsively and copy the values to new objects.
* @param b1
* @return b2
*/
public Shallow deepCopy(){
Shallow b = new Shallow();
b.setTwo(this.getTwo());
if(this.getA()!=null){
Deep a = new Deep();
a.setOne(this.getA().getOne());
b.setA(a);
}
return b;
}
/**
* Unoptimized deep copy using serialization.
* @return B
*/
public Shallow unOptimizedDeepCopy() {
Shallow b = null;
try {
// Write the object out to a byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(this);
out.flush();
out.close();
// Make an input stream from the byte array and read
// a copy of the object back in.
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
b = (Shallow) in.readObject();
}catch(IOException e) {
e.printStackTrace();
}catch(ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
return b;
}
}

Clone Demo :

package com.lenin.clone;
public class CloneDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Deep a = new Deep();
a.setOne("one");
Shallow b = new Shallow();
b.setA(a);
b.setTwo("Two");
Shallow b1 = b.clone();//shallow copy
Shallow b2 = b.shallowCopy();
Shallow b3 = b.deepCopy();
Shallow b4 = b.unOptimizedDeepCopy();//depp copy with serialization.
//Modifying internal ojbect after created new objects.
a.setOne("one-one");
//Shallow : Using clone
if(b1!=null && b1 instanceof Shallow){
System.out.println(b1.getA().getOne());
System.out.println(b1.getTwo());
}
//Shallow : Manual
if(b2!=null && b2 instanceof Shallow){
System.out.println(b2.getA().getOne());
System.out.println(b2.getTwo());
}

//Deep : Optimized (Manual)
if(b3!=null && b3 instanceof Shallow){
System.out.println(b3.getA().getOne());
System.out.println(b3.getTwo());
}
//Deep : Unoptimized (Using serialization)
if(b4!=null && b4 instanceof Shallow){
System.out.println(b4.getA().getOne());
System.out.println(b4.getTwo());
}
}
}