Sunday, February 22, 2015

Cloning Objects in Java

In Java, objects are manipulated through reference variables, and there is no operator for copying an object—the assignment operator duplicates the reference, not the object. The clone() method provides this missing functionality. In this article, we look into the basic of cloning in Java and types of cloning such as shallow and deep cloning. Also, it disadvantages  and  what are the alternative approach to do the cloning in Java.




Java does not provide an automatic mechanism to clone (make a copy) an object. Recall that when you assign a reference variable to another reference variable, only the reference of the object is copied, not the content of the object. 
Cloning an object means copying the content of the object bit by bit. If you want objects of your class to be cloned, you must re-implement the clone() method in your class. Once you re-implement the clone() method, you should be able to clone objects of your class by calling the clone() method. The declaration of the clone() method in the Object class is as follows:

protected Object clone() throws CloneNotSupportedException


You need to observe few things about the declaration of the clone() method.

  • It is declared protected. Therefore, you will not be able to call it from the client code. The following code is not valid:Object obj = new Object();Object clone = obj.clone(); // Error. Cannot access protected clone() method.This means you need to declare the clone() method public in your class if you want the client code to clone objects of your class.
  • Its return type is Object. It means you will need to cast the returned value of the clone() method. Suppose MyClass is Cloneable. Your cloning code will look as
    MyClass mc = new MyClass();
    MyClass clone = (MyClass)mc.clone(); // Need to use a cast

You do not need to know any internal details about an object to clone it. The clone() method in the Object class has all the code that is needed to clone an object. All you need is to call it from the clone() method of your class. It will make a bitwise copy of the original object and return the reference of the copy.
The clone() method in the Object class throws a CloneNotSupportedException . It means when you call the clone() method of the Object class, you need to place the call in a try-catch block, or re-throw the exception.You have the option not to throw a CloneNotSupportedException from the clone() method of your class

The following snippet of code is placed inside the clone() method of your class, which calls the clone() method of the Object class using the super keyword:
One important thing that you must do is add an "implements Cloneable" clause in your class declaration. Cloneable is an interface declared in the java.lang package.Otherwise, you will get a runtime error when you call the clone() method on the objects of your class.

Example

Once your class implements the clone() method correctly, cloning an object of your class is as simple as calling its clone() method
At this point, there are two separate objects of the Burger class. The veg variable references the original object and vegClone variable references the clone of the original object. The original as well as the cloned object hold the same value of 100. However, they have separate copies of the value. If you change the value in the original object, for example, vegClone.setBurgerPrice(200), the value in the cloned object remains unchanged. Let see the tester class
From Java 5, you need not specify the return type of the clone() method in your class as the Object type. You can specify your class as the return type in the clone() method declaration. This will not force the client code to use a cast when it call the clone() method of your class.
With the above declaration for the clone() method, you can write code to clone an object as follows. Note that no cast is needed anymore

The standard pattern for making a class cloneable is:
  1. Implement Cloneable
  2. Override the clone() method and make it public
  3. In clone() call super.clone() and then copy any mutable object's state
You should not create a new object using new. The proper way is to call super.clone() for a new instance. Object's clone() is special and will create a new copy of the object and copy its primitive fields and references.

Shallow Cloning
An object may be composed of another object. In such cases, two objects exist in memory separately—a contained object and a container object. The container object stores the reference of the contained object. When you clone the container object, the reference of the contained object is cloned. After cloning is performed, there are two copies of the container object; both of them have references to the same contained object. This is called a shallow cloning because references are copied, not the objects. The clone() method of the Object class makes only shallow cloning, unless you code it otherwise.


Example ShallowClone 

An object of the ShallowClone class is composed of an object of the Burger class. The code in the clone() method of the ShallowClone class is the same as for the clone() method of the Burger class. The difference lies in the type of instance variables that are used for the two classes. The Burger class has an instance variable of primitive type int, whereas the ShallowClone class has an instance variable of the reference type DoubleHolder. When the ShallowClone class calls the clone() method of the Object class (using super.clone()), it receives a shallow copy of itself. That is, it shares the Burger object used in its instance variable with its clone.

Following code test an object of the ShallowClone class and its clone. The output shows that after you make a clone, changing the value through the original object also changes the value in the cloned object. This is so because the ShallowClone object stores the value in another object of the Burger class, which is shared by both the cloned and the original objects.



Deep Cloning
When the contained objects are copied rather than their references during cloning of a compound object, it is called deep cloning. You must clone all the objects referenced by all reference variables of an object to get a deep cloning.
A compound object may have multiple levels of chaining of contained objects. For example, the container object may have a reference of another contained object, which in turn has a reference of another contained object and so on. Whether you will be able to perform a deep cloning of a compound object depends on many factors. If you have a reference of a contained object, it may not support cloning and in that case, you have to be content with shallow cloning. You may have a reference of a contained object, which itself is a compound object. However, the contained object supports only shallow cloning, and in that case again, you will have to be content with shallow cloning.

In a deep cloning, you need to clone all objects referenced by all reference instance variables of an object. You must perform a shallow cloning before you can perform a deep cloning. The shallow cloning is performed by calling the clone() method of the Object class. Then you will need to write code to clone all reference instance variables.

Example DeepClone 

If you compare the code in the clone() method of the ShallowClone and DeepClone classes, you will find that for deep cloning you had to write only one extra line of code.


copy.burger = (Burger)this.burger.clone();

What will happen if the Burger class is not cleanable? In that case, you would not be able to write the above statement to clone the holder instance variable. You could have cloned the burger instance variable as follows:

copy.burger = new Burger(this.burger.getValue());

The goal is to clone the burger instance variable and it does not have to be done by calling its clone() method



Clone Method
In order for implementing the Cloneable interface to have any effect on a class, it and all of its superclasses must obey a fairly complex, unenforceable, and largely undocumented protocol. It creates an object without calling a constructor. The general contract for the clone method is weak. Here it is, copied from the specification for java.lang.Object:




Tip
Using the clone() method of the Object class is not the only way to make a clone of an object. You can use other methods to clone an object. You may provide a copy constructor, which accepts an object of the same class and creates a clone of that object. You may provide a factory method in your class, which may accept an object and returns its clone. Another way to clone an object is to serialize it and then deserialized it.

The copy constructor approach and its static factory variant have many advantages over Cloneable/clone:

  • They do not rely on a risk-prone extralinguistic object creation mechanism Where as in clonealbe, In order for implementing the Cloneable interface to have any effect on a class, it and all of its superclasses must obey a fairly complex, unenforceable, and largely undocumented protocol. The resulting mechanism is extralinguistic: It creates an object without calling a constructor.
  • They do not conflict with the proper use of final fields where in cloneable, If a class is not final, `clone` has to return the most derived class for which it was called. That can't work with a constructor, because `clone` doesn't know which one to call. If a class is final, it can't have any subclasses, so there's no danger in calling its constructor when cloning.
  • They do not require the client to catch an unnecessary checked exception, where it require clonealbe require the client to handle the exception.
  • They provide a statically typed object to the client.



If you know anyone who has started learning java, why not help them out! Just share this post with them. Thanks for studying today!...

5 comments: