Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Cloneable type as parameter to Java generic class

I have a generic class that needs to be able to clone objects of the parameter type. A very simple example is below. The compiler claims clone() from the type Object is not visible.

public class GenericTest<T extends Cloneable>
    {
    T obj;
    GenericTest(T t)
        {
        obj = t;
        }
    T getClone()
        {
        // "The method clone() from the type Object is not visible."
        return (T) obj.clone();
        }
    }

I'd prefer not to have the caller do the cloning since there are other things that have to happen to maintain the integrity of the object. The code above is just an illustration of the problem without the noise of the other data I have to maintain related to the cloned object.

Is there a way around this or is this another one of those cases where the designers of Java consider rationalizing its shortcomings the equivalent of having none?

like image 614
Craig Avatar asked Jan 20 '23 04:01

Craig


2 Answers

Because the method is marked as protected on the Object class, you cannot in general call this method on arbitrary objects. Personally I didn't think this would be a problem at first (hey, I'm a subclass of Object, so I should be able to call its protected methods, right?), but the compiler needs to know that you're a subclass of the target object's class (or in its package) in order to call protected methods, neither of which apply here.

The idea behind the clone() method is that classes which supported it would override the method, declaring it as public.

The only real solution here that preserves full functionality is to use reflection to access the method and get around the access modifiers. An alternative would be to write your own MyCloneable interface which has a public clone() method declared on it; this might work if you'll only ever be passing your own domain classes in, but means that you couldn't use it on external classes (such as java.util.String or java.util.ArrayList) since you can't force them to implement your interface.

As per answers to the linked question, this is a very dubious design.

like image 177
Andrzej Doyle Avatar answered Jan 31 '23 04:01

Andrzej Doyle


A mistake on Java's part. Reflection is the right way to go

static Method clone = Object.class.getMethod("clone"); 

static public <T extends Cloneable> 
T clone(T obj)
    return (T) clone.invoke(obj);
like image 36
irreputable Avatar answered Jan 31 '23 04:01

irreputable