Réponses:
Le fait que le clone soit protégé est extrêmement douteux - tout comme le fait que la clone
méthode ne soit pas déclarée dans l' Cloneable
interface.
Cela rend la méthode assez inutile pour prendre des copies de données car vous ne pouvez pas dire :
if(a instanceof Cloneable) {
copy = ((Cloneable) a).clone();
}
Je pense que la conception de Cloneable
est maintenant largement considérée comme une erreur (citation ci-dessous). Je voudrais normalement pouvoir faire des implémentations d'une interface Cloneable
mais pas nécessairement faire l'interfaceCloneable
(similaire à l'utilisation de Serializable
). Cela ne peut se faire sans réflexion:
ISomething i = ...
if (i instanceof Cloneable) {
//DAMN! I Need to know about ISomethingImpl! Unless...
copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}
Citation de Effective Java de Josh Bloch :
"L'interface clonable était conçue comme une interface mixin pour que les objets annoncent qu'ils permettent le clonage. Malheureusement, cela ne sert pas à cette fin ... Il s'agit d'une utilisation très atypique des interfaces et non d'une utilisation à émuler ... Pour que l’implémentation de l’interface ait un effet sur une classe, celle-ci et toutes ses superclasses doivent obéir à un protocole assez complexe, inapplicable et largement non documenté »
Serializable
- c'est aux implémentations de décider de l'implémenter Serializable
. J'étendais cela à Cloneable
- ce n'est pas quelque chose qu'une interface devrait étendre - mais une implémentation d'une interface est libre de l'être Cloneable
. Le problème est que si vous avez un paramètre du type interface, vous lui demandez s'il est clonable; mais alors vous ne pouvez pas réellement le cloner!
L'interface clonable n'est qu'un marqueur indiquant que la classe peut prendre en charge le clonage. La méthode est protégée car vous ne devez pas l'appeler sur un objet, vous pouvez (et devriez) la remplacer comme publique.
Du soleil:
Dans la classe Object, la méthode clone () est déclarée protégée. Si tout ce que vous faites est d'implémenter Cloneable, seuls les sous-classes et les membres du même package pourront invoquer clone () sur l'objet. Pour permettre à n'importe quelle classe de n'importe quel package d'accéder à la méthode clone (), vous devrez la remplacer et la déclarer publique, comme ci-dessous. (Lorsque vous substituez une méthode, vous pouvez la rendre moins privée, mais pas plus privée. Ici, la méthode protected clone () dans Object est remplacée en tant que méthode publique.)
Set
clone
est protégé car c'est quelque chose qui doit être remplacé pour qu'il soit spécifique à la classe actuelle. Bien qu'il soit possible de créer une clone
méthode publique qui clonerait n'importe quel objet, cela ne serait pas aussi bon qu'une méthode écrite spécifiquement pour la classe qui en a besoin.
La méthode Clone ne peut être utilisée directement sur aucun objet, c'est pourquoi elle est destinée à être remplacée par la sous-classe.
Bien sûr, cela pourrait être public et simplement lancer une exception appropriée lorsque le clonage n'est pas possible, mais je pense que ce serait trompeur.
La façon dont le clone est implémenté actuellement vous fait réfléchir à la raison pour laquelle vous souhaitez utiliser le clonage et à la manière dont vous souhaitez que votre objet soit cloné.
Il est protégé car l'implémentation par défaut fait une copie superficielle de tous les champs (y compris privé), en contournant le constructeur . Ce n'est pas quelque chose qu'un objet peut être conçu pour gérer en premier lieu (par exemple, il peut garder une trace des instances d'objet créées dans une liste partagée, ou quelque chose de similaire).
Pour la même raison, l'implémentation par défaut de clone()
lancera si l'objet sur lequel elle est appelée ne l'implémente pas Cloneable
. C'est une opération potentiellement dangereuse avec des conséquences importantes, et par conséquent, l'auteur de la classe doit explicitement s'y inscrire.
Du javadoc de cloneable.
* By convention, classes that implement this interface (cloneable) should override
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.
* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface. Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.
Vous pouvez donc appeler clone sur chaque objet, mais cela ne vous donnera la plupart du temps pas les résultats que vous souhaitez ou une exception. Mais n'est encouragé que si vous implémentez clonable.
À mon humble avis, c'est aussi simple que ceci:
#clone
ne doit pas être appelé sur des objets non clonables, il n'est donc pas rendu public#clone
doit être appelée par les sous-classes ob Object
qui implémentent Cloneable pour obtenir la copie superficielle de la bonne classeQuelle est la bonne portée pour les méthodes qui doivent être appelées par des sous-classes, mais pas par d'autres classes?
C'est protected
.
Les classes implémentant Cloneable
bien sûr rendront cette méthode publique afin qu'elle puisse être appelée à partir d'autres classes.
La méthode Clone () a une vérification interne `` instance de Cloneable ou non ''. C'est ainsi que l'équipe Java pourrait penser qu'elle limitera l'utilisation incorrecte de la méthode clone () method.clone () est protégée, c'est-à-dire accessible par les sous-classes uniquement. Puisque l'objet est la classe parente de toutes les sous-classes, la méthode Clone () peut être utilisée par toutes les classes en fait si nous n'avons pas la vérification ci-dessus de 'instance de Cloneable'. C'est la raison pour laquelle l'équipe Java aurait pu penser à restreindre l'utilisation incorrecte de clone () en vérifiant dans la méthode clone () 'is it instance of Cloneable'.
Par conséquent, toutes les classes implémentées clonables peuvent utiliser la méthode clone () de la classe Object.
De plus, comme il est protégé, il n'est disponible que pour les sous-classes qui implémentent une interface clonable. Si nous voulons la rendre publique, cette méthode doit être remplacée par la sous-classe avec sa propre implémentation.
Oui, même problème que j'ai rencontré. Mais je le résous en implémentant ce code
public class Side implements Cloneable {
public Side clone() {
Side side = null;
try {
side = (Side) super.clone();
} catch (CloneNotSupportedException e) {
System.err.println(e);
}
return side;
}
}
Tout comme l'a dit quelqu'un avant.
Eh bien, les développeurs Sun ne sont également qu'humains, et ils ont en effet commis une énorme erreur en implémentant la méthode de clonage comme protégée, la même erreur en implémentant une méthode de clonage qui ne fonctionnait pas dans ArrayList! Donc, en général, il existe un malentendu beaucoup plus profond des programmeurs Java même expérimentés sur la méthode de clonage.
Cependant, j'ai récemment trouvé une solution rapide et facile pour copier n'importe quel objet avec tout son contenu, peu importe comment il est construit et ce qu'il contient, voir ma réponse ici: Bug dans l'utilisation d'Object.clone ()
Encore une fois, le framework Java JDK montre une pensée brillante:
L'interface clonable ne contient pas de "clone T public ();" parce qu'elle agit plus comme un attribut (par exemple. Serializable) qui permet à une instance d'être clonée.
Il n'y a rien de mal avec cette conception car:
Object.clone () ne fera pas ce que vous voulez avec votre classe personnalisée.
Si vous avez Myclass implémente Cloneable => vous remplacez clone () par "public MyClass clone ()"
Si vous avez MyInterface étend Cloneable et certaines MyClasses implémentant MyInterface: définissez simplement "public MyInterface clone ();" dans l'interface et chaque méthode utilisant des objets MyInterface pourra les cloner, quelle que soit leur classe MyClass.