Il est certainement vrai que Object.clone()
ne fait quelques choses qui ne peuvent simplement pas être réalisés en Java.
De Josh Bloch on Design: Copy Constructor versus Cloning (Souligné par l'auteur):
méthode clone de l'objet est très délicat. C'est basé sur des copies de terrain, et c'est "extra-linguistique".Il crée un objet sans appeler un constructeur. Il n'y a aucune garantie qu'il préserve les invariants établis par les constructeurs.
Object.clone()
fait quelque chose qui n'est pas censé être autorisé par le langage. C'est pourquoi, parmi beaucoup d'autres raisons, clone()
est cassé.
(Si vous n'avez pas déjà, vous devriez aussi lire son livre Effective Java, de comprendre pourquoi il (et bien d'autres) pensent que Java et de clone()
Cloneable
est cassé).
Si vous voulez juste créer un objet de la même classe qu'un autre objet quelconque, alors c'est en fait tout à fait réalisable, avec une mise en garde (à savoir que tous les types sont accessibles au public instanciable) en utilisant la réflexion.
Voici un exemple de comment utiliser la réflexion pour:
- Découvrez la classe d'un objet à l'exécution
- Liste de ses champs déclarés, les méthodes et les constructeurs
- Trouver son constructeur de copie (le cas échéant) et tente de l'appeler en utilisant l'objet donné comme paramètre .
import java.lang.reflect.*;
public class NewInstance {
static void print(String label, Object[] arr) {
System.out.println(label);
for (Object o : arr) {
System.out.println(o);
}
System.out.println("---");
}
static Object newInstance(Object o) {
Class<?> c = o.getClass();
System.out.println("Class is " + c);
print("FIELDS:", c.getDeclaredFields());
print("METHODS:", c.getDeclaredMethods());
print("CONSTRUCTORS:", c.getDeclaredConstructors());
try {
Constructor<?> cc = c.getDeclaredConstructor(c);
o = cc.newInstance(o);
} catch (NoSuchMethodException e) {
System.out.println("No copy constructor found!");
} catch (IllegalAccessException e) {
System.out.println("Copy constructor inaccessible!");
} catch (InstantiationException e) {
System.out.println("Instantiation failed!");
} catch (InvocationTargetException e) {
System.out.println("Copy constructor threw " + e.getCause());
}
return o;
}
public static void main(String args[]) {
Object o1 = "hello";
Object o2 = newInstance(o1);
boolean success = (o1 != o2) && (o1.equals(o2));
System.out.println("Attempt " + (success ? "succeeded!" : "failed :("));
}
}
Sortie:
Class is class java.lang.String
FIELDS:
// (omitted)
METHODS:
// (omitted)
CONSTRUCTORS:
public java.lang.String()
public java.lang.String(java.lang.String) // this is what we're looking for!
// (rest omitted)
---
Attempt succeeded!
Notez que ceci est juste un exemple pour montrer le type peut être inspecté au moment de l'exécution et un constructeur de copie peut être recherchée et invoqué. Tel quel, cela ne fonctionne pas si o
est un ArrayList
, car il n'a aucun constructeur qui prend un ArrayList
(il en a un qui prend un Collection
, qu'un ArrayList
est).
Je vais vous laisser un exercice sur la façon d'étendre la recherche du constructeur de copie pour inclure ces surcharges compatibles.
Qu'essayez-vous d'accomplir? Si ce n'est que du code, écrivez-le explicitement. –
Ce code ne compile même pas et n'a aucun sens. Vérifiez la réponse de Savvas Dalkitsis. Vous devez clarifier davantage ce que vous souhaitez accomplir exactement. – BalusC
Doit faire plus de sens maintenant .. –