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 Ob开发者_C百科ject 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?
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.
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);
I needed to clone a POJO with fields in it. What did work was the following:
public static Object clone(Object o)
{
Object clone = null;
try
{
clone = o.getClass().newInstance();
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
// Walk up the superclass hierarchy
for (Class obj = o.getClass();
!obj.equals(Object.class);
obj = obj.getSuperclass())
{
Field[] fields = obj.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
fields[i].setAccessible(true);
try
{
// for each class/suerclass, copy all fields
// from this object to the clone
fields[i].set(clone, fields[i].get(o));
}
catch (IllegalArgumentException e){}
catch (IllegalAccessException e){}
}
}
return clone;
}
精彩评论