Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to clone a Java object with the clone() method

Tags:

java

clone

I don't understand the mechanism of cloning custom object. For example:

public class Main{

    public static void main(String [] args) {

        Person person = new Person();
        person.setFname("Bill");
        person.setLname("Hook");

        Person cloned = (Person)person.clone();
        System.out.println(cloned.getFname() + " " + cloned.getLname());
    }
}

class Person implements Cloneable{

    private String fname;
    private String lname;

    public Object clone() {

        Person person = new Person();
        person.setFname(this.fname);
        person.setLname(this.lname);
        return person;
    }

    public void setFname(String fname) {
        this.fname = fname;
    }

    public void setLname(String lname){
        this.lname = lname;
    }

    public String getFname(){
        return fname;
    }

    public String getLname() {
        return lname;
    }
}

This is example shows right way of cloning as a in the books write. But I can delete implements Cloneable in the class name definition and I receive the same result.

So I don't understand the proposing of Cloneable and why clone() method is defined in class Object?

like image 208
Dima Zelinskyi Avatar asked Sep 28 '11 07:09

Dima Zelinskyi


People also ask

How do you clone an object in Java?

Creating a copy using the clone() method The class whose object's copy is to be made must have a public clone method in it or in one of its parent class. Every class that implements clone() should call super. clone() to obtain the cloned object reference. The class must also implement java.

What does clone () do in Java?

The class Object 's clone() method creates and returns a copy of the object, with the same class and with all the fields having the same values. However, Object. clone() throws a CloneNotSupportedException unless the object is an instance of a class that implements the marker interface Cloneable .

Does clone () make a deep copy?

clone() is indeed a shallow copy. However, it's designed to throw a CloneNotSupportedException unless your object implements Cloneable . And when you implement Cloneable , you should override clone() to make it do a deep copy, by calling clone() on all fields that are themselves cloneable.

How many ways we can clone object in Java?

There are two types of object cloning - shallow cloning, and deep cloning. Let's understand each of them and find out the best way to implement cloning in our Java programs.


5 Answers

The clone method is meant to make a deep copy. Make sure you understand the difference between deep and shallow copies. In your case a copy constructor may be the pattern you want. In some cases you can't use this pattern however, for example because you're subclassing class X and you don't have access to the constructor of X that you need. If X overrides its clone method correctly (if necessary) then you could make a copy in the following way:

class Y extends X implements Cloneable {

    private SomeType field;    // a field that needs copying in order to get a deep copy of a Y object

    ...

    @Override
    public Y clone() {
        final Y clone;
        try {
            clone = (Y) super.clone();
        }
        catch (CloneNotSupportedException ex) {
            throw new RuntimeException("superclass messed up", ex);
        }
        clone.field = this.field.clone();
        return clone;
    }

}

In general when overriding your clone method:

  • Make the return type more specific
  • Start with calling super.clone()
  • Do not include throws clause when you know clone() will also work for any subclass (weakness of the clone-pattern; make class final if possible)
  • Leave immutable and primitive fields alone, but clone mutable object fields manually after the call to super.clone() (another weakness of the clone-pattern, since these fields cannot be made final)

The clone() method of Object (which will eventually be called when all superclasses obey the contract) makes a shallow copy and takes care of the correct runtime type of the new object. Note how no constructor is called in the entire process.

If you want to be able to call clone() on instances, then implement the Cloneable interface and make the method public. If you don't want to be able to call it on instances, but you do want to make sure subclasses can call their super.clone() and get what they need, then don't implement Cloneable and keep the method protected if your superclass hasn't declared it public already.

The clone pattern is difficult and has a lot of pitfalls. Be sure it's what you need. Consider copy constructors, or a static factory method.

like image 73
Rinke Avatar answered Sep 28 '22 08:09

Rinke


The JVM is able to clone the object for you, and you're thus not supposed to construct a new person by yourself. Just use this code:

class Person implements Cloneable {
    // ...
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

or

class Person implements Cloneable {
    // ...
    @Override
    public Object clone() {
        try {
            return super.clone();
        }
        catch (CloneNotSupportedException e) {
            throw new Error("Something impossible just happened");
        }
    }
}

This will work even if the Person class is subclassed, whereas your clone implementation will always create an instance of Person (and not an instance of Employee for an Employee, for example).

like image 35
JB Nizet Avatar answered Sep 28 '22 08:09

JB Nizet


The clone() in class Object does a shallow copy of the memory instead of calling methods like the constructor. In order to call clone() on any object that doesn't implement clone() itself, you need to implement the Clonable interface.

If you override the clone() method you don't have to implement that interface.

Just as the JavaDoc says, this would result in an exception:

class A {
  private StringBuilder sb; //just some arbitrary member
}

...

new A().clone(); //this will result in an exception, since A does neither implement Clonable nor override clone()

If A in the example would implement Clonable calling clone() (the Object version) would result in a new A instance that references the very same StringBuilder, i.e. changes to sb in the cloned instance would result in changes to the sb in the original A instance.

That's meant with a shallow copy and that one reason why it is generally better to override clone().

Edit: just as a sidenote, using return type covariance would make your overridden clone() more explicit:

public Person clone() {
  ...
}
like image 21
Thomas Avatar answered Sep 28 '22 06:09

Thomas


There's no need to create the object explicitly here in clone() method. Just by calling super.clone() will create the copy of this object. It will perform the shallow clone.

like image 37
Gaurav Agarwal Avatar answered Sep 28 '22 07:09

Gaurav Agarwal


clone is not mature as Joshua bloch say:

http://www.artima.com/intv/bloch13.html

like image 29
rt.jar Avatar answered Sep 28 '22 06:09

rt.jar