Rabu, 13 Agustus 2014

How clone method works in Java




clone is a tricky method from java.lang.Object
class, which is used to create copy of an Object in Java. Intention of clone() method is
simple, to provide a cloning mechanism, but some how it's implementation became
tricky and has been widely criticized from long time. Anyway, we will not go to
classic debate of clone in Java, at-least for now; instead, we will try to
learn how clone method works in Java.
To be fair, understating cloning mechanism in Java is not easy and even
experienced Java programmer fail to explain how cloning of mutable object works,
or difference between deep copy and shallow copy in Java. In this three part article, we will first see working
of
clone method in Java, and in second part we will learn how to override
clone method in Java
, and finally we will discuss deep copy vs shallow copy mechanism. The reason I chose to make
this a three part article, is to keep focus on one thing at a time. Since
clone() itself is
confusing enough, it's best to understand concept one by one. In this post, we
will learn what is clone method, what it does and How clone method works in
Java. By the way, clone() is one of the few fundamental methods defined by
objects, others being equals, hashcode(), toString() along with wait and notify methods.







What is clone of object in Java



An object which is returned by clone() method is known as clone of
original instance. A clone object should follow basic characteristics e.g.
a.clone()
!= a
, which means original and clone are two separate object in Java heap, a.clone().getClass()
== a.getClass()
and clone.equals(a), which
means clone is exact copy of original object. These characteristic is followed
by a well behaved, correctly overridden
clone() method in
Java, but it's not enforced by cloning mechanism. Which means, an object
returned by
clone() method may violate any of these
rules. By following convention of returning object by calling
super.clone(), when
overriding
clone() method, you can ensure that it
follows first two characteristics. In order to follow third characteristic, you
must override equals method to
enforce logical comparison, instead of physical comparison exists in
java.lang.Object. For
example,
clone() method of Rectangle class in
this method return object, which has these characteristics, but if you run same
program by commenting equals(), you will see that
third invariant i.e.
clone.equals(a) will return false. By the way there are couple of good items on Effective Java regarding effective use of clone method, I highly recommend to read those items after going through this article.





How Clone method works in Java



How Clone method works in Javajava.lang.Object provides default implementation
of
clone() method in Java. It's declared as protected and native in Object
class, so implemented in native code. Since it's convention to return
clone() of object
by calling super.clone() method, any cloning process eventually reaches to
java.lang.Object clone()
method. This method, first checks if corresponding object implements
Cloneable interface,
which is a marker interface. If that instance doesn't implements Cloneable then
it throws
CloneNotSupported in Java, a checked
exception, which is always required to be handled while cloning an object. If
object pass this check, than
java.lang.Object's clone() method
creates a shallow copy of object and returned it to the caller. Since Object
class'
clone() method creates copy by creating
new instance, and then copying
field-by-field, similar
to assignment operator, it's fine for primitives and Immutable object, but not
suited if your class contains some mutable data-structure e.g. Collection
classes like ArrayList or arrays. In that case, both
original object and copy of object will point to the same object in heap. You
can prevent this by using technique known as deep cloning, on which each
mutable field is cloned separately. In short, here is how clone method works in
Java :





1) Any class calls clone() method on instance, which
implements
Cloneable and overrides protected clone() method
from
Object class, to create a copy.






  Rectangle rec = new Rectangle(30,
60);


  logger.info(rec);


      


    try
{


         logger.info("Creating Copy of this object
using Clone method"
);


         Rectangle copy = rec.clone();


         logger.info("Copy " + copy);


          


    } catch
(CloneNotSupportedException ex) {


         logger.debug("Cloning is not supported for
this object"
);


    }






2) Call to clone() method on Rectangle is
delegated to
super.clone(), which can be a custom super class or by default java.lang.Object






    @Override


    protected
Rectangle clone() throws CloneNotSupportedException {


        return
(Rectangle) super.clone();


    }






3) Eventually call reaches to java.lang.Object's clone() method,
which verify if corresponding instance implements
Cloneable interface,
if not then it throws
CloneNotSupportedException, otherwise
it creates a field-by-field copy of instance of that class and returned to
caller.





So in order for clone() method to work properly, two
things need to happen, a
Class should implement Cloneable interface
and should override
clone() method of Object class. By
the way this was this was the simplest example of overriding clone method and
how it works, things gets more complicated with real object, which contains
mutable fields, arrays, collections, Immutable object and
p
rimitives, which we will see in second part of this Java Cloning tutorial
series.





Java clone() method Example



In this article, we have not seen complexity of overriding clone method
in Java, as our
Rectangle class is very simple and only
contains primitive fields, which means shallow cloning provided by Object's
clone() method is
enough. But, this example is important to understand process of Object cloning
in Java, and How clone method works. Here is complete code of this
clone() method
overriding example :






import org.apache.log4j.Logger;





/**


  * Simple example of overriding clone() method
in Java to understand How Cloning of


  * Object works in Java.


  *


  * @author


 */


public class JavaCloneTest
{


    private
static final
Logger logger = Logger.getLogger(JavaCloneTest.class);


  


    public
static void
main(String args[]) {





        Rectangle rec = new Rectangle(30,
60);


        logger.info(rec);


      


        Rectangle copy = null;


        try
{


            logger.info("Creating Copy of this object
using Clone method"
);


            copy = rec.clone();


            logger.info("Copy " + copy);


          


        } catch
(CloneNotSupportedException ex) {


            logger.debug("Cloning is not supported for
this object"
);


        }


      


        //testing
properties of object returned by clone method in Java


        logger.info("copy != rec : " +
(copy != rec));


        logger.info("copy.getClass() ==
rec.getClass() : "
+ (copy.getClass()
== rec.getClass()));


        logger.info("copy.equals(rec) : "
+ copy.equals(rec));


      


        //Updating
fields in original object


        rec.setHeight(100);


        rec.setWidth(45);


      


        logger.info("Original object :" +
rec);


        logger.info("Clonned object  :" + copy);


    }


 


}





public class Rectangle
implements Cloneable{


    private
int width;


    private
int height;


  


    public
Rectangle(int
w, int h){


        width = w;


        height = h;


    }





    public
void setHeight(int height) {


        this.height = height;


    }





    public
void setWidth(int width) {


        this.width = width;


    }


  


    public
int area(){


        return
widthheight;


    }


  


    @Override


    public
String toString(){


        return
String.format("Rectangle [width: %d, height: %d, area: %d]",
width, height, area());


    }





    @Override


    protected
Rectangle clone() throws CloneNotSupportedException {


        return
(Rectangle) super.clone();


    }





    @Override


    public
boolean equals(Object
obj) {


        if
(obj == null) {


            return
false;


        }


        if
(getClass() != obj.getClass()) {


            return
false;


        }


        final
Rectangle other = (Rectangle) obj;


        if
(this.width
!= other.width) {


            return
false;


        }


        if (this.height != other.height)
{


            return
false;


        }


        return
true;


    }





    @Override


    public
int hashCode()
{


        int
hash = 7;


        hash = 47  hash + this.width;


        hash = 47  hash + this.height;


        return
hash;


    }


  


  


  


}





Output:


2013-05-20
23:46:58,882
0   
[main] INFO  JavaCloneTest  - Rectangle [width:
30, height:
60, area:
1800]


2013-05-20
23:46:58,882
0   
[main] INFO  JavaCloneTest  - Creating Copy of this object using Clone method


2013-05-20
23:46:58,882
0   
[main] INFO  JavaCloneTest  - Copy Rectangle [width:
30, height:
60, area:
1800]





2013-05-20
23:46:58,882
0   
[main] INFO  JavaCloneTest  - copy != rec : true


2013-05-20
23:46:58,882
0   
[main] INFO  JavaCloneTest  - copy.getClass()
== rec.getClass() : true


2013-05-20
23:46:58,882
0   
[main] INFO  JavaCloneTest  - copy.equals(rec)
: true





2013-05-20
23:46:58,882
0   
[main] INFO  JavaCloneTest  - Original object :Rectangle [width: 45,
height: 100,
area: 4500]





2013-05-20
23:46:58,882
0   
[main] INFO  JavaCloneTest  - Cloned object  :Rectangle [width:
30, height:
60, area:
1800]






From output, you can clearly see that cloned object has same attribute as
original object in Java. Also changing attribute of original object is not
affecting state of copy object, because they only contains primitive fields,
had then contain any mutable object, it would have affected both of them. You
can also see that it follow standard properties of cloned object i.e.
clone
!= original
, clone.getClass() == original.getClass() and clone.equals(original).





Things to Remember - Clone method in Java






1) Clone method is used to create a copy of object in Java. In order to
use
clone() method, class must implement java.lang.Cloneable interface and override
protected
clone() method from java.lang.Object. A
call to
clone() method will result in CloneNotSupportedException, if that
class doesn't implement
Cloneable interface.





2) No constructor is called during cloning of Object in Java.





3) Default implementation of clone() method in
Java provides "shallow copy"
of object, because it creates copy of Object by creating new instance and then
copying content by assignment, which means if your Class contains a mutable
field, then both original object and clone will refer to same internal object.
This can be dangerous, because any change made on that mutable field will
reflect in both original and copy object. In order to avoid this, override
clone() method to
provide deep copy of object.





4) By convention, clone of an instance should be obtained by calling super.clone() method,
this will help to preserve invariant of object created by
clone() method
i.e.
clone != original and clone.getClass() ==
original.getClass()
. Though these are not absolute requirement as
mentioned in Javadoc.





5) Shallow copy of an instance is find, until it only contains primitives
and Immutable objects, otherwise, you need to modify one or more mutable fields
of object returned by super.clone, before returning it to caller.





That's all on How clone method works in Java. Now we know, what is
clone and what is
Cloneable interface, couple of things about
clone method and what does default implementation of
clone method do
in Java. This information is enough to move ahead and read second part of this
Java cloning tutorial, on which we will learn, how to override
clone() method in Java, for classes
composed with primitives, Mutable and Immutable objects in Java.




Recommended Book

Like most of important topics in Java, Joshua Bloch has shared some words of wisdom on object cloning and clone method in Java. I highly suggest going through those items on his evergreen Effective Java book.



























Source:http://javarevisited.blogspot.com/2013/09/how-clone-method-works-in-java.html

Tidak ada komentar:

Posting Komentar