Notice

╠ This is my personal blog and my posts here have nothing to do with my employers or any other association I may have. It is my personal blog for my personal experience, ideas and notes. ╣

Monday, June 22, 2015

Java Cloning


I recently watched trailer of "Jurassic World", where scientists are again cloning DNA of thousands years old dinosaur.


Let refresh our memory and see how the word cloning fit into Java world.

What is cloning ?

"In biology, cloning is the process of producing similar populations of genetically identical individuals that occurs in nature when organisms."
-- Wikipedia

Here the term "genetically identical" need attention for Java developers for doing cloning of objects. We will look into the details later.

Java provide a method which help us to create "genetically identical" copy of object. It is achieved through clone() method, which is inside Object class.

Now lets see why Java provide a method to create object. If we create a new object then the state of the object is initialized, but what if we need a current state of object but at the same time we didn't want to disturb the current object.

For Example :- 
Suppose you have an object X which is a singleton object and shared across application. In this scenario suppose a module need an object of X which will be changed the state of the object temporally but this will affect other module also. In this kind of scenario we need a clone of object.  

How to clone an object ? 

We can clone only those classes object which implements the Cloneable interface else it will result into CloneNotSupportedException exception.
Cloneable interface is a markup interface like Serializable interface. Cloneable interface is used to indicate that a class allows a bit wise copy of an object to be made.

Please note clone method does not invoke the constructor of target.


Simple example of Cloning.

Clone.java
  1. /**
  2. * @Author Anindya Bandopadhyay
  3. *
  4. * com\ch1\clone\Clone.java
  5. *
  6. * @Created on Jun 22, 2015 5:49:02 PM
  7. */
  8. package com.ch1.clone;
  9. public class Clone implements Cloneable{
  10.  
  11.  @Override
  12. public Object clone() throws CloneNotSupportedException {
  13.    return super .clone();
  14. }
  15. public Object cloneThis(){
  16. Object object = null;
  17. try {
  18. object = clone();
  19. } catch (CloneNotSupportedException e) {
  20. e.printStackTrace();
  21. }
  22. return object;
  23. }
  24. }
CloneTester.java
  1. /**
  2. * @Author Anindya Bandopadhyay
  3. *
  4. * com\ch1\CloneTester.java
  5. *
  6. * @Created on Jun 22, 2015 10:51:40 AM
  7. */
  8. package com.ch1.clone;
  9. public class CloneTester {
  10. public static void main(String[] args) {
  11. Clone actual = new Clone();
  12. Clone clone = (Clone) actual.cloneThis();
  13. System.out.printf("Is both object are same ? %s",(actual == clone));
  14. }
  15. }
Output of the source code 
Is both object are same ? false

As I earlier mention that we need to pay special attention to "genetically identical". Genetically identical means even if by cloning an object we get a new object but this new object will hold same data and/or object references.
This objects are known as Shallow Copy Object. While using cloning we have to be very careful as this shared object references between actual and clone object.
To mitigate this shared object references we use another technique which is known as Deep Copy Object. In this technique we create new object and copy the values, so that it will not interfere each others object processing.

Just think of the situation where we have a shared I/O object between two objects, where one is trying to writing something into it and another is trying to close it.This kind of situation leads to catastrophe in running environment because of this in Object class clone() method is protected so that if developer cannot simple clone an object. It must be overridden carefully and used by a different public method. 

Lets see how Shallow and Deep copy objects references works.

Shallow Copy Object is achieved by simple invoking super.clone() method.

  
ShallowClone.java
  1. /**
  2. * @Author Anindya Bandopadhyay
  3. *
  4. * com\ch1\clone\ShallowClone.java
  5. *
  6. * @Created on Jun 15, 2015 2:24:22 PM
  7. */
  8. package com.ch1.clone;
  9. public class ShallowClone implements Cloneable {
  10. private Object obj1;
  11. private int count;
  12. public ShallowClone(){
  13. obj1 = new Object();
  14. count = 1;
  15. System.out.println("Default constructor of CloneImpl.");
  16. }
  17. public ShallowClone(Object obj1,int size){
  18. this.obj1 = obj1;
  19. this.count = size;
  20. System.out.println("CloneImpl(InnerCloneObject obj1,int size) constructor of CloneImpl.");
  21. }
  22. public Object getObj1() {
  23. return obj1;
  24. }
  25. public void setObj1(Object obj1) {
  26. this.obj1 = obj1;
  27. }
  28. public int getCount() {
  29. return count;
  30. }
  31. public void setCount(int count) {
  32. this.count = count;
  33. }
  34. protected Object clone() throws CloneNotSupportedException{
  35. return super.clone();
  36. }
  37. public ShallowClone cloneThisObject(){
  38. ShallowClone object = null;
  39. try {
  40. System.out.println("\n======================= Start Clone ============================");
  41. object = (ShallowClone) clone();
  42. System.out.println("======================= End Clone ============================");
  43. } catch (CloneNotSupportedException e) {
  44. e.printStackTrace();
  45. }
  46. return object;
  47. }
  48. }
Deep Copy Object is need to be take care by developer. clone() method is override with respect to specific requirement.

Please note this can be achieve even without overriding the clone() method also. We can simple put the logic directly inside cloneThisObject() method.

DeepClone.java
  1. /**
  2. * @Author Anindya Bandopadhyay
  3. *
  4. * com\ch1\clone\DeepClone.java
  5. *
  6. * @Created on Jun 19, 2015 12:12:26 AM
  7. */
  8. package com.ch1.clone;
  9. public class DeepClone implements Cloneable {
  10. private String name;
  11. private Object obj1;
  12. public DeepClone(){
  13. name = "Andy";
  14. obj1 = new Object();
  15. System.out.println("Default constructor of InnerCloneObject.");
  16. }
  17. public DeepClone(String name,Object obj1){
  18. this.name = name;
  19. this.obj1 = obj1;
  20. System.out.println("InnerCloneObject(String name,Object obj1) constructor of InnerCloneObject.");
  21. }
  22. public String getName() {
  23. return name;
  24. }
  25. public void setName(String name) {
  26. this.name = name;
  27. }
  28. public Object getObj1() {
  29. return obj1;
  30. }
  31. public void setObj1(Object obj1) {
  32. this.obj1 = obj1;
  33. }
  34. protected Object clone() throws CloneNotSupportedException{
  35. // Customize clone logic is placed.
  36. System.out.println("\n======================= Start Clone ============================");
  37. DeepClone object = new DeepClone();
  38. System.out.println("======================= End Clone ============================");
  39. return object;
  40. }
  41. public DeepClone cloneThisObject(){
  42. DeepClone object = null;
  43. try {
  44. object = (DeepClone) clone();
  45. } catch (CloneNotSupportedException e) {
  46. e.printStackTrace();
  47. }
  48. return object;
  49. }
  50. }
Lets upgrade CloneTester class for Shallow and Deep copy objects.

CloneTester.java
  1. /**
  2. * @Author Anindya Bandopadhyay
  3. *
  4. * Chapter1\com\ch1\CloneTester.java
  5. *
  6. * @Created on Jun 22, 2015 10:51:40 AM
  7. */
  8. package com.ch1.clone;
  9. public class CloneTester {
  10. public static void main(String[] args) {
  11. ShallowClone shallowActualObject = new ShallowClone();
  12. DeepClone deepActualObject = new DeepClone();
  13. ShallowClone shallowCloneObject = shallowActualObject.cloneThisObject();
  14. DeepClone deepCloneObject = deepActualObject.cloneThisObject();
  15. System.out.printf("Is ShallowClone actual object are different from clone object ? %s ",
  16. (shallowActualObject != shallowCloneObject));
  17. System.out.printf("\nIs object inside ShallowClone object are different ? %s \n",
  18. (shallowActualObject.getObj1() == shallowCloneObject.getObj1()));
  19. System.out.printf("Is DeepClone actual object are different from clone object ? %s ",
  20. (deepActualObject != deepCloneObject));
  21. System.out.printf("\nIs object inside DeepClone object are different ? %s ",
  22. (deepActualObject.getObj1() == deepCloneObject.getObj1()));
  23. }
  24. } 
Output of the source code 
Default constructor of ShallowClone.
Default constructor of DeepClone.

======================= Start Clone ============================
======================= End Clone   ============================

======================= Start Clone ============================
Default constructor of DeepClone.
======================= End Clone   ============================
Is ShallowClone actual object are different from clone object ? true
Is object inside ShallowClone object are different ? true
Is DeepClone actual object are different from clone object ? true
Is object inside DeepClone object are different ? false

Shallow Copy Object Graph
Shallow Copy Object
Shallow Copy Object


Deep Copy Object Graph
Deep Copy Object
Deep Copy Object
Just compare the outputs and object graphs. By these we can deceive that how important for developer to pay attention to need of cloning or overriding the clone() method.

If you have any question or feedback please comment.