Pergunta

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?

Foi útil?

Solução

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);

Outras dicas

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.

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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top