How do i convince the compiler an Object is cloneable (java)?

425 Views Asked by At

i want to clone a given object.

if i do this

public class Something{
    Object o; //set in the constructor
    public Something(Object o){
         this.o = o;}
    public Something clone() throws CloneNotSupportedException{
         Something temp = super.clone();
         if (o instanceof Cloneable) //important part
             temp.o = o.clone(); //important part
         else temp.o = o;
    }
}

this will not work becuase o.clone() is protected.

if i do this instead

         if (o instanceof Cloneable) //important part
             temp.o = ((Cloneable)o).clone(); //important part

it won't work either because Cloneable is an empty interface.

so how do i convince the compiler that you can clone o?

5

There are 5 best solutions below

0
On

There is no general way to clone an object in Java. The type must provide a method to clone (which may be called clone() or something else; doesn't matter) in its public API, and there is no common supertype for such types in Java.

0
On

You can't, when implementing clone() one must know what is cloning, must know the implementation class.

An alternative to cloning is to use copy-constructor, that has the same issue, you must know the class.

Some say do not use clone, others say define your own interface, eg: Copyable http://c2.com/cgi/wiki?CloneableDoesNotImplementClone

0
On

Alternative would be to use serialization if it's possible to implement Serializable interface. Downside is the performance ofcourse.

https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/SerializationUtils.html#clone(java.io.Serializable)

If you don't want to use apache commons you could do the same thing using ObjectOutputStream/ObjectInputStream.

1
On

The java.lang.Cloneable interface must be implemented by the class whose object clone we want to create. If we don't implement Cloneable interface, clone() method generates CloneNotSupportedException.

The clone() method is defined in the Object class. Syntax of the clone() method is as follows:

protected Object clone() throws CloneNotSupportedException

So your class should be as

public class Something implements Cloneable {

    private Object o; //set in the constructor

    public Something(Object o) {
        this.o = o;
    }

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

    public Object getObject() {
        return o;
    }

    public static void main(String[] args) {
        Something s = new Something("try");
        System.out.println(s.getObject());
        try {
            Something s2 = (Something) s.clone();
            System.out.println(s2.getObject());
        } catch (CloneNotSupportedException ex) {
            Logger.getLogger(Something.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
0
On

You can do it with reflection

//We need reflection
import java.lang.reflect.*;
    //This class is the backbone of the feature
    public class MyCloneable implements Cloneable {

        //A constructor. For the sake of simplicity, the constructor is an empty constructor.
        public MyCloneable() {}

        //We implement the clone method. This returns a clone
        protected Object clone() throws CloneNotSupportedException {
            //We need the class of the object
            class c = this.getClass();
            //We get the empty constructor of the object
            Constructor constructor = c.getConstructor(new Class[]{});
            //newClone will be the cloned object
            Object newClone = constructor.newInstance(new Object[]{});
            //We get the array of fields
            Field[] fields = c.getDeclaredFields();
            //We iterate the fields to copy them. You might want to close these too, but for the sake of simplicity I did not tackle with this issue
            for (int fieldIndex = 0; fieldIndex < fields.length; fieldIndex++) {
                //We copy the field values of this into the clone
                fields[fieldIndex].set(newClone, fields[fieldIndex].get(this));
            }
            //newClone is ready and kicking
            return newClone;
        }

        //We need this method to be able to reach the clone method publicly
        public Object runClone() throws CloneNotSupportedException {
            return this.clone();
        }

    }

This code is untested, any observation is welcome.

You need to use objects of classes which are inherited from MyCloneable.