Wednesday, May 20, 2015

Understanding Cloning in Java : Swallow vs Deep


Cloning is to create a copy of an object. And both original and cloned object should hold same values in their object graph. This article is to about how cloning works in java and different types of cloning.

Must implement Clonable Interface

Object class has a method called clone() to enable cloning of any object in Java. A class should implement Clonable interface to successfully invoke clone method of its object. If a class does not implement Clonable interface, then invoking clone() method on its object will throw CloneNotSupportedException.

Example :
class Example1{
....
}
class Example2 implements Clonable{
....
}
// Throw CloneNotSupportedException
Example1 example1Clone = (Example1)new Example1().clone();   
// Clone Successfully
Example2 example2Clone = (Example2)new Example2().clone();

Always Create A New Instance

When you call clone method of any Clonable object then it  create a new instance. So original object and cloned object are always 2 different instances.

Example :
class Example implements Cloneable{
...
}
// Create an object
Example original = new Example();
// Clone an object
Example cloned = (Example)original.clone();
// 2 different instances 
object == cloned; // false

Swallow Cloning

By default java does swallow cloning for you. In swallow cloning, a new instance of the original object is created but the instance variables in both original object and cloned object refer to same instances.

Example :

class MyObject {
   int value;
   public MyObject(int value){
       this.value = value;
   }
   public int getValue(){
     this.value;
   }
}

class Example implements Cloneable{
   MyObject myObject;
   public Example(MyObject myObject){
       this.myObject = myObject;
   }
   public MyObject getMyObject(){
       return this.myObject;
   }
}

// Create Original Object
Example original = new Example(new MyObject(55));
// Create Cloned Object
Example cloned = (Example)original.clone();
// Instance variable of both refering to same object instance 
original.getMyObject() == cloned.getMyObject(); // true
// So the values in both should be same
original.getMyObject().getvalue()== cloned.getMyObject().getvalue();

Deep Cloning

In deep cloning original object's  object graph and cloned object's object graph should not share any common object, they should have their own copy in their object graph. To achieve deep cloning,you need to override the default clone method. To ensure implementing deep cloning , create the whole object graph by copying the values manually inside clone method.

Example :

class MyObject {
   int value;
   public MyObject(int value){
       this.value = value;
   }
   public int getValue(){
     this.value;
   }
}

class Example implements Cloneable {
   MyObject myObject;
   public Example(MyObject myObject){
       this.myObject = myObject;
   }
   public MyObject getMyObject(){
       return this.myObject;
   }
   @Override
   public Object clone()throws CloneNotSupportedException {
      MyObject myObject = new MyObject(this.myObject.getValue());
      return new Example(myObject);
   }
}

// Create Original Object
Example original = new Example(new MyObject(55));
// Create Cloned Object
Example cloned = (Example)original.clone();
// Instance variable of both refering to different object instances 
original.getMyObject() == cloned.getMyObject(); // false
// But the values in both should be same
original.getMyObject().getvalue()== cloned.getMyObject().getvalue();


Sometimes it is very difficult to implement clone method for deep cloning, specially when of very complex or big object graph involved. So in such cases safe way is to serialize the object, then deserialize. This ensures everything is a brand new reference.  Example Here

2 comments:

  1. Nice examples of clone in java. Just check the first example you have given Example1 class should throw excpetion because it doesn't implement Clonable marker interface not the Example2 class. Further great article on clone http://javapapers.com/core-java/java-clone-shallow-copy-and-deep-copy/

    ReplyDelete