Wednesday, August 4, 2021

How clone method works in Java? Example

The clone() is a tricky method from java.lang.Object class, which is used to create a copy of an object in Java. The intention of the clone() method is simple, to provide a cloning mechanism, but somehow its implementation became tricky and has been widely criticized for a long time. Anyway, we will not go to the classic debate of clones in Java, at least for now; instead, we will try to learn how the clone method works in Java. To be fair, understating the cloning mechanism in Java is not easy and even experienced Java programmers fail to explain how cloning of mutable objects works, or the difference between deep and shallow copy in Java.

In this three-part article, we will first see the working of the clone method in Java, and in the second part we will learn how to override the clone method in Java, and finally, we will discuss the deep copy vs shallow copy mechanism.

The reason I chose to make this a three-part article is to keep the focus on one thing at a time. Since clone() itself is confusing enough, it's best to understand concepts one by one. In this post, we will learn what is clone method is, what it does, and How the 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 the clone of an object in Java?

An object which is returned by the clone() method is known as a clone of the 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. 

This characteristic is followed by a well-behaved, correctly overridden clone() method in Java, but it's not enforced by the cloning mechanism. This means an object returned by the clone() method may violate any of these rules.

By following the convention of returning an object by calling super.clone(), when overriding the clone() method, you can ensure that it follows the first two characteristics. In order to follow the third characteristic, you must override the 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 the same program by commenting equals(), you will see that third invariant i.e. clone.equals(a) will return false

By the way, there are a couple of good items on Effective Java regarding the effective use of the clone method, I highly recommend reading 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 the Object class, so implemented in native code. Since its convention to return clone() of an object by calling super.clone() method, any cloning process eventually reaches to java.lang.Object clone() method. 

This method first checks if the corresponding object implements Cloneable interface, which is a marker interface. If that instance doesn't implement Cloneable then it throws CloneNotSupportedException in Java, a checked exception, which is always required to be handled while cloning an object. If an object passes this check, then java.lang.Object's clone() method creates a shallow copy of the 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 the original object and copy of the object will point to the same object in the heap. You can prevent this by using the technique known as deep cloning, on which each mutable field is cloned separately. In short, here is how the clone method works in Java:



1) Any class calls clone() method on an 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 superclass 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 the corresponding instance implements Cloneable interface, if not then it throws CloneNotSupportedException, otherwise it creates a field-by-field copy of the instance of that class and returned to the 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 primitives, which we will see in second part of this Java Cloning tutorial series.

Here is how  a shallow copy of an object looks like:

How to override clone() method in Java?


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 the 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 the output, you can clearly see that cloned object has the same attribute as the original object in Java. Also changing the attribute of an original object is not affecting the state of copy object because they only contain primitive fields. If they had contained 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) The clone() method is used to create a copy of an 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 the object because it creates a copy of Object by creating a 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 the same internal object. 

This can be dangerous because any change made on that mutable field will reflect in both the original and copy object. In order to avoid this, override the clone() method to provide the deep copy of an 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) A shallow copy of an instance is fine until it only contains primitives and Immutable objects, otherwise, you need to modify one or more mutable fields of the object returned by super.clone(), before returning it to the caller.


That's all on How the clone method works in Java. Now we know, what is the clone and what is Cloneable interface is, a couple of things about the clone method, and what does default implementation of the clone method does in Java. 

This information is enough to move ahead and read the second part of this Java cloning tutorial, on which we will learn, how to override the clone() method in Java, for classes composed of primitives, mutable and immutable objects in Java.

20 comments :

Anonymous said...

"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"

So hashcode is different but equals should return true. Isn't this a violation of the equals-hashcode contract?

Anonymous said...

How do you relate hash code here... ?
c the hash code calculation in above rectangle class.. its has nothing to do with the reference of the object..
I have a question.. Why is clone method protected by implementation ?

Anonymous said...

Why it is protected - so that you can't call it on any object - the default shallow copy can be risky unless the class explicitly says its ok. Classes should override it, return the appropriate type (instead of Object) and make the visibility public.
http://stackoverflow.com/questions/1138769/why-is-the-clone-method-protected-in-java-lang-object

Sasi kumar said...

HI, even hashcode is different , but equals should return true, it is not violation of equal-hashcode contract, because if two objects having same hashcode, those objects value may be same , may not be same. but when two objects having same value, both objects hashcode must be same.

Anonymous said...

please provide the links for the 2nd and 3rd part of the clone article

Anonymous said...

Return type of OVERRIDDEN clone method is Object in superclass, how can it be narrower i.e. Rectangle in subclass? Please correct me if I am wrong.

Unknown said...

"Anonymous said...
Return type of OVERRIDDEN clone method is Object in superclass, how can it be narrower i.e. Rectangle in subclass? Please correct me if I am wrong."
--> Java overriding rule: 'The return type should be the same or a subtype of the return type declared in the original overridden method in the superclass'

VINOD said...

Does Cloning makes use of reflection? If yes could you please explain why and how?

Thanks.

Anonymous said...

"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."

Can't find second part!!!

Unknown said...

A Cloneable interface which gives permission to clone() method in a given program which throws CloneNotSupportedException.U can check it more clearly in this video.https://youtu.be/kzOrWHgRe4A

uday said...

This here what listed is Example of Shallow copy right ???

javin paul said...

@Uday, yes it's an example of shallow cloning, but given the object is Immutable it didn't really matter. See the second part of this article for cloning an object with the mutable field, which involves deep copy.

Unknown said...

Point 3 :
"This can be dangerous because any change made on that mutable field will reflect in both original and copy object.
"
We can make changes if an object is Mutable.

Unknown said...

If equals() method returns true the the hashcode() must be equal,but reverse may or may not be equal.This is the only contract.

Unknown said...

Hi, can you please tell me what is the user of a clone method ?
Is an instance of a cloned object?

javin paul said...

@Adrian, clone is used to create copy of an object e.g. if you have a Date you can create another Date object by using clone, which has same attributes or state as previous Date object.

Ansu said...

Very nice article, just one correction, you said the clone method will work perfectly in case of immutable objects and primitive but in the 'Shallow copy' image, you have used String class which is immutable and pointing to same reference and that is not correct.

javin paul said...

Hello ansu, in case of Immutable object, multiple reference can point to same object, that's the whole purpose of making it object immutable. Since it cannot be changed, its safe to share.

Unknown said...

ansu, I had the same question as your after reading this article, but as Paul pointed out, the shadow copy is actually having all fields pointing to the same reference in heap; given that it is safe to point to the same reference for immutable/primitive objects, shadow copy is safe enough if the class only contains immutable/primitive objects.

The second part of this series elaborates this in the first paragraph as well: https://javarevisited.blogspot.com/2014/03/how-to-clone-collection-in-java-deep-copy-vs-shallow.html

javin paul said...

Thank you @Unknown for taking initiative and explaining to fellow reader. Much appreciated and yes, you are absolutely correct.

Post a Comment