Pregunta

Tengo una clase genérica que necesita poder clonar objetos del tipo de parámetro. Un ejemplo muy simple está a continuación. El compilador afirma clone () del objeto tipo no es 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();
        }
    }

Prefiero no que la persona que llama haga la clonación ya que hay otras cosas que tienen que suceder para mantener la integridad del objeto. El código anterior es solo una ilustración del problema sin el ruido de los otros datos que tengo que mantener relacionados con el objeto clonado.

¿Hay alguna manera de evitar esto o es este otro de esos casos en los que los diseñadores de Java consideran racionalizar sus deficiencias el equivalente a no tener ninguno?

¿Fue útil?

Solución

Un error por parte de Java. La reflexión es el camino correcto a seguir

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

static public <T extends Cloneable> 
T clone(T obj)
    return (T) clone.invoke(obj);

Otros consejos

Porque el método está marcado como protected sobre el Object clase, en general no puede llamar a este método en objetos arbitrarios. Personalmente no pensé que esto sería un problema al principio (oye, soy una subclase de Object, así que debería poder llamar a sus métodos protegidos, ¿verdad?), Pero el compilador necesita saber que eres una subclase del objeto objetivoLa clase (o en su paquete) para llamar a métodos protegidos, ninguno de los cuales se aplica aquí.

La idea detrás del clone() El método es que las clases que lo respaldaron anularían el método, declarándolo como public.

La única solución real aquí que preserva la funcionalidad completa es usar la reflexión para acceder al método y evitar los modificadores de acceso. Una alternativa sería escribir la tuya MyCloneable interfaz que tiene un público clone() método declarado en él; Esto podría funcionar si alguna vez solo está pasando sus propias clases de dominio, pero significa que no podría usarlo en clases externas (como java.util.String o java.util.ArrayList) ya que no puede obligarlos a implementar su interfaz.

Según las respuestas al pregunta vinculada, este es un diseño muy dudoso.

Necesitaba clonar un pojo con campos en él. Lo que funcionó fue lo siguiente:

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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top