Sunday 7 May 2017

Cloning

Cloning plays very important role in Java programming. It's one of the easiest way of creating replica of your Java object.


1. What is cloning in Java?

AnswerCloning is a way of creating replica of any given Java object. It's way of creating a new object without using the new keyword. 
Object that we create through cloning may or may not have the same state of all the properties of original object.


2. How to clone a Java object?

AnswerIn order to perform clone operation below steps need to follow:
1. Implement java.lang.Clonable marker interface in the class whose objects you are going to clone.
2. Override the clone() method defined in Object class.
Example: In below code which is very self explanatory, our Human class is cloanable. We have overrided the clone() method of Object class where we have called super.clone() in order to utilize default implementation of clone() method as it is in Object class. 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class CloneExample {

 public static void main(String[] args) throws CloneNotSupportedException {
  Human human1 = new Human();
  human1.setName("John Mathew");
  human1.setAge(28);
  
  Human human2 = (Human) human1.clone();
  
  System.out.println("Human1 details---> Name: "+ human1.getName()+ ", Age: "+human1.getAge());
  System.out.println("Human2 details---> Name: "+ human2.getName()+ ", Age: "+human2.getAge());
 }

}

class Human implements Cloneable{
 private String name;
 private Integer age;
 
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public Integer getAge() {
  return age;
 }
 public void setAge(Integer age) {
  this.age = age;
 }
 
 @Override
 protected Object clone() throws CloneNotSupportedException {
  return super.clone();
 }
}
  
In above code we have created a new(copy) object human2 at line number 8 by calling clone() method. human2 object has same value of all the properties as human1 object.
This is the advantage of cloning that you get copy of original object just by calling clone() method, the alternative manual approach will be create a new object and then copy value of all the properties from original object to copied object. If a class will have a lot of properties then  manual effort will much more. 

3. How many types of cloning Java supports?

AnswerThere are two types of cloning Java supports:
1. Shallow cloning or Shallow copy: This is the default behavior of clone() method. In above code clone() method performs shallow copy but since we don't have any mutable custom type it will work as deep copy.
If your class have only primitive and Immutable types then above code will work fine. But if you code have the mutable custom classes than you need to take care of them while cloning.
2. Deep cloning or Deep copy: This is the special case where we need to handle custom classes(non primitive and mutable classes).

Below is the example of shallow copy. Here we have custom mutable class Department. At line number 16 we have updated the deptId of department object of org2 only. But when we have printed the details of both the object of Organization after update we saw that value of deptId also got updated for department object of org1 object. 
And the reason is due to shallow copy both the objects, original object org1 and cloned object org2 sharing the same department object instead of having their own copy like other properties orgName and years.

NoteFor all mutable custom class Java doesn't perform deep copy by default instead it passes the reference of same object to the cloned object.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public class ShallowCopyExample {

 public static void main(String[] args) throws CloneNotSupportedException {
  Department dept1 = new Department();
  dept1.setDeptId(111111);
  Oragnization org1 = new Oragnization();
  org1.setOrgName("ABC Corp");
  org1.setYears(28);
  org1.setDepartment(dept1);
  
  Oragnization org2 = (Oragnization) org1.clone();
  
  System.out.println("Oragnization1 details---> Name: "+ org1.getOrgName()+ ", Years: "+org1.getYears() + ", Dept Id:"+org1.getDepartment().getDeptId());
  System.out.println("Oragnization2 details---> Name: "+ org2.getOrgName()+ ", Years: "+org2.getYears() + ", Dept Id:"+org2.getDepartment().getDeptId());
  
  org2.getDepartment().setDeptId(222222);
 
  System.out.println("********************************************After Update***********************************************");
  System.out.println("Oragnization1 details---> Name: "+ org1.getOrgName()+ ", Years: "+org1.getYears() + ", Dept Id:"+org1.getDepartment().getDeptId());
  System.out.println("Oragnization2 details---> Name: "+ org2.getOrgName()+ ", Years: "+org2.getYears() + ", Dept Id:"+org2.getDepartment().getDeptId());
 }
}

class Oragnization implements Cloneable{
 private String orgName;
 private Integer years;
 private Department department;
 
 
 public String getOrgName() {
  return orgName;
 }
 public void setOrgName(String orgName) {
  this.orgName = orgName;
 }
 public Integer getYears() {
  return years;
 }
 public void setYears(Integer years) {
  this.years = years;
 }
 public Department getDepartment() {
  return department;
 }
 public void setDepartment(Department department) {
  this.department = department;
 }


 @Override
 protected Object clone() throws CloneNotSupportedException {
  return super.clone();
 }
}
 class Department implements Cloneable{
   private Integer deptId;

   public Integer getDeptId() {
   return deptId;
  }

  public void setDeptId(Integer deptId) {
   this.deptId = deptId;
  }

  @Override
  protected Object clone() throws CloneNotSupportedException {
   return super.clone();
  }
 }

Just replace the clone method of Organization class in above code with below code and run the code. This time you will get the desire result as only deptId of org2 will be updated and deptId of org1 will remain same. This implantation of clone known as deep copy.

1
2
3
4
5
6
@Override
 protected Object clone() throws CloneNotSupportedException {
  Oragnization orgTemp = (Oragnization) super.clone();
  orgTemp.setDepartment((Department)orgTemp.getDepartment().clone());
  return orgTemp;
 }

Fig : Shallow Copy
Fig : Deep Copy
Above two figure clearly explain how shallow and deep copy behaves. In case of shallow copy as you can see we have only one object of Department refer by both the objects of Organization, but in deep copy we have cloned the object of Department as well hence we have two different object of Department. 

4. Why we need cloning and where we use it?

AnswerCloning is the simple and fast way of creating exact copy of existing object.
Now assume you have an object with say 20 properties, Now if your requirement says you need to have copy of same object. In this case if you don't use cloning then you need to perform below steps for clone:
1. create new object using conventional new keyword.
2. Read the value of properties from original object and set it into new object one by one.
As you can see above process required a lot of extra effort just to copy one object. 
Cloning is useful when creating a new object is quite costly using conventional approach.
Use of Cloning: It is clear that whenever we want a copy of original object we use cloning. There are few places where we use cloning like Prototype design pattern and Immutable classes.

5. What is copy constructor?

AnswerCopy constructor is a another way of making copy of an object.  Since clone() method which is defined inside Object class creates the copy of object without using Java constructor unlike standard object creation process in Java. Hence copy constructor is alternative approach to clone() method which uses constructor to create object.
Example:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class CopyConstructorExample {
 public static void main(String[] args) throws CloneNotSupportedException {
  Human human1 = new Human();
  human1.setName("John Mathew");
  human1.setAge(28);

  Human human2 = new Human(human1);

  System.out.println("Human1 details---> Name: "+ human1.getName()+ ", Age: "+human1.getAge());
  System.out.println("Human2 details---> Name: "+ human2.getName()+ ", Age: "+human2.getAge());
 }
}


class Human{
 private String name;
 private Integer age;

 public Human(){
  //Normal constructor
 }
 public Human(Human human){
  //Copy constructor
  this.name = human.getName();
  this.age = human.getAge();
 }
 
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public Integer getAge() {
  return age;
 }
 public void setAge(Integer age) {
  this.age = age;
 }
}
In above code I've used same example that I have used above in question 2 for clone() method. But this time I've used copy constructor instead at line number 22 you can see. Also point to note there is no need to implement Cloneable interface.

Note: 1. Java does support copy constructor same as C++ but like C++ it doesn't provide default copy constructor for you. As we saw in above code we need to provide copy constructor by our self.

2. You should prefer copy constructor above clone() method for copy operation. One of the reason as I said before copy constructor uses conventional approach of constructor which makes things consistent throughout.
Also note that according to Joshua Bloch "Cloneable interface is broken". Please read here explanation by him for the same. 

No comments:

Post a Comment