Come usare il tipo clonaugabile come parametro per la classe generica Java
Domanda
Ho una classe generica che deve essere in grado di clonare oggetti del tipo di parametro. Un esempio molto semplice è sotto. Il compilatore rivendica clone () dall'oggetto tipo non è visibile.
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();
}
}
Preferirei non far sì che il chiamante faccia la clonazione poiché ci sono altre cose che devono accadere per mantenere l'integrità dell'oggetto. Il codice sopra è solo un'illustrazione del problema senza il rumore degli altri dati che devo mantenere relativo all'oggetto clonato.
C'è un modo per aggirare questo o è un altro di quei casi in cui i progettisti di Java considerano razionalizzare le sue carenze l'equivalente di non averne nessuno?
Soluzione
Un errore da parte di Java. La riflessione è la strada giusta per andare
static Method clone = Object.class.getMethod("clone");
static public <T extends Cloneable>
T clone(T obj)
return (T) clone.invoke(obj);
Altri suggerimenti
Perché il metodo è contrassegnato come protected
sul Object
Classe, non puoi in generale chiamare questo metodo su oggetti arbitrari. Personalmente non pensavo che questo sarebbe stato un problema all'inizio (ehi, sono una sottoclasse di Object
, quindi dovrei essere in grado di chiamare i suoi metodi protetti, giusto?), Ma il compilatore deve sapere che sei una sottoclasse del Oggetto targetLa classe (o nel suo pacchetto) per chiamare metodi protetti, nessuno dei quali si applica qui.
L'idea alla base del clone()
il metodo è che le classi che lo supportano avrebbero sovrascritto il metodo, dichiarandolo come public
.
L'unica vera soluzione qui che preserva la piena funzionalità è quella di utilizzare la riflessione per accedere al metodo e aggirare i modificatori di accesso. Un'alternativa sarebbe scrivere il tuo MyCloneable
interfaccia che ha a pubblico clone()
metodo dichiarato su di esso; Questo potrebbe funzionare se solo superate le tue lezioni di dominio, ma significa che non potresti usarlo su classi esterne (come java.util.String
o java.util.ArrayList
) dal momento che non puoi costringerli ad implementare la tua interfaccia.
Secondo le risposte al Domanda collegata, questo è un design molto dubbio.
Avevo bisogno di clonare un pojo con campi. Ciò che ha funzionato era il seguente:
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;
}