Thursday, 24 February 2011

Clone, Cloneable, Deep and Shallow Clone


CLONE and CLONEABLE:
Clone is a protected method defined in Object class. To clone any class that class should must implement Cloneable interface which is a marker interface otherwise it will through CloneNotSupportedException. 
Cloneable is a marker interface so no method defined. Interesting thing is it does not support Generics probably because it was there before Generics or for backward compatibility.
Cloneable Vs Serialization:
Cloneable interface is used to make a clone of a object,every time create a new instance by new operator is costly in terms of JVM ,resource & performance. so we can create similar type of instance with the help of already been created instance by using clone()


Serialization is a process to convert your object into bitstream and send accross the network and deserialze at other end,process like Marshling. By default serialization dies Deep Copy.



SHALLOW COPY vs DEEP COPY:
Shallow copies duplicate as little as possible. A shallow copy of a collection is a copy of the collection structure, not the elements. With a shallow copy, two collections now share the individual elements.
Deep copies duplicate everything. A deep copy of a collection is two collections with all of the elements in the original collection duplicated.

How to do SHALLOW COPY:
For shallow copy we can clone() method but make sure all field reference classes should also be Cloneable.

How to do DEEP COPY:

Solution 1: Use Copy Constructor

class DeepCloneableClass {
   //Define other constructor as usual

   //Copy Constructor for deep cloning
   public DeepCloneableClass(DeepCloneableClass from){
      this.field1  = from.getField1();
      ...
      ...
   }
}


Solution 2: Use Factory Pattern 

class DeepCloneableClass {

//Create factory method for deep cloning
    public static DeepCloneableClass fromInstance(DeepCloneableClass from){
        new DeepCloneableClass(from.getFeild1());
        ...
    }
}

Solution 3: Force by new Interface like DeepCloneable


interface DeepCloneable<T>{            
    //In implementaion create deep copy
    public T deepClone(T t);
}



Example Showing Difference Between Deep and Shallow Copy:
************************************************

package com.object;


class Person implements Cloneable {
// Lower-level object
private Car car;


private String name;


public Car getCar() {
return car;
}


public String getName() {
return name;
}


public void setName(String s) {
name = s;
}


public Person(String s, String t) {
name = s;
car = new Car(t);
}


public Object deepClone() {
// Deep copy
Person p = new Person(name, car.getName());
return p;
}


public Object shallowClone() {
// shallow copy
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
}


class Car {


private String name;


public String getName() {
return name;
}


public void setName(String s) {
name = s;
}


public Car(String s) {
name = s;
}
}


public class DeepNShallowCopyTest {


public static void main(String[] args) {
// Original Object
Person p = new Person("Person-A", "Civic");
System.out.println("Original (orginal values): " + p.getName() + " - "
+ p.getCar().getName());


// Clone as a shallow copy
Person q = (Person) p.shallowClone();


System.out.println("Clone (before change): " + q.getName() + " - "
+ q.getCar().getName());


// change the primitive member
q.setName("Person-B");


// change the lower-level object
q.getCar().setName("Accord");


System.out.println("Clone (after change): " + q.getName() + " - "
+ q.getCar().getName());


System.out.println("Original (after clone is modified): " + p.getName()
+ " - " + p.getCar().getName());


System.out.println("********************************");


// Original Object
Person dp = new Person("Person-A", "Civic");
System.out.println("Original (orginal values): " + dp.getName() + " - "
+ dp.getCar().getName());


// Clone as a shallow copy
Person dq = (Person) dp.deepClone();


System.out.println("Clone (before change): " + dq.getName() + " - "
+ dq.getCar().getName());


// change the primitive member
dq.setName("Person-B");


// change the lower-level object
dq.getCar().setName("Accord");


System.out.println("Clone (after change): " + dq.getName() + " - "
+ dq.getCar().getName());


System.out.println("Original (after clone is modified): "
+ dp.getName() + " - " + dp.getCar().getName());


}
}

OUTOUT :

Original (orginal values): Person-A - Civic
Clone (before change): Person-A - Civic
Clone (after change): Person-B - Accord
Original (after clone is modified): Person-A - Accord
********************************
Original (orginal values): Person-A - Civic
Clone (before change): Person-A - Civic
Clone (after change): Person-B - Accord
Original (after clone is modified): Person-A - Civic

No comments:

Post a Comment