7
votes

Pourquoi Java Enums n'est-elle pas clonable?

Il est trop tard pour changer la question, mais plus précis aurait été de demander "pourquoi le clone () ne permet pas aux singletons?". Une méthode copie () serait plus pratique.


Y a-t-il une raison pour laquelle Enums en Java ne peut pas être cloné?

Le manuel indique que

Ceci garantit que les Enums ne sont jamais clonées, ce qui est nécessaire pour préserver leur statut "singleton".

Mais le retour de l'instance elle-même préserverait également son statut et je serais en mesure de gérer les énumes associées de la même manière que d'autres objets clignables.

On peut soutenir que

L'intention générale [de clone ()] est que, pour tout objet X, l'expression: x.clone ()! = x sera vrai, [...]

mais pour les singletons au contraire, je veux x.clone () == x pour être vrai. Si l'instance elle-même serait renvoyée, le modèle singleton serait transparent pour référencer des objets.

Alors pourquoi les énumes ne sont-elles pas autorisées à être clonées ou ont-elles oublié de penser à des singletons et d'immutables, lorsque clone () a été spécifié?


1 commentaires

Avec des énumérations, qu'est-ce qu'il y a à cloner?


6 Réponses :


1
votes

Je suppose qu'ils ne voulaient pas traiter des singletons comme cas spécial lorsque clone () a été spécifié. Cela aurait compliqué la spécification. Alors maintenant, les développeurs de la bibliothèque doivent les traiter comme cas particulier, mais pour le reste de nous, c'est bien que nous puissions faire confiance à ce x.clone ()! = X . .


0 commentaires

7
votes

Si votre méthode de clone renvoie cette instance plutôt qu'un objet distinct, ce n'est pas un clone, est-ce?

Le Javadoc dit:

par convention, l'objet renvoyé par Cette méthode devrait être indépendante de cet objet (qui est cloné).

Enums ne sont pas censés être clonés car il est censé être supposé être un exemple de chaque valeur.

EDIT: En réponse au commentaire suivant :

C'est exactement ce que je critiquez. Pourquoi ne pas renvoyer la même instance, s'il y a ne peut pas être un autre?

Parce que cela n'a pas vraiment de sens. Si c'est le même objet, ce n'est pas un clone. Les Javadocs disent également:

L'intention générale est que, pour tout objet x, l'expression: xxx sera vrai, et que le expression: xxx sera vrai, mais ces ne sont pas des exigences absolues.

L'intention est pour la méthode clone () pour renvoyer un objet distinct. Malheureusement, il est dit que ce n'est pas une exigence absolue, qui rend votre suggestion valide, mais je pense toujours que ce n'est pas sensible car il n'est pas utile d'avoir une méthode clone qui renvoie ce . Cela pourrait même causer des problèmes si vous faites quelque chose de douteux comme ayant un état mutable dans vos constantes d'enum ou de la synchroniser. Le comportement de ce code serait différent selon que la méthode du clone a fait du clonage approprié ou vient de renvoyer ceci .

Vous n'expliquez pas vraiment pourquoi vous voulez traiter Enums comme clonable quand ils sont intrinsèquement non claquables. Voulant avoir une méthode clone qui n'obéit pas aux conventions acceptées semble être un hack pour résoudre un problème plus fondamental avec votre approche.


3 commentaires

Parce que le "contrat" ​​de la méthode clone est de renvoyer une copie.


@Stephen C: Oui, mais tous les objets ne doivent pas adhérer à ce contrat, c'est-à-dire que toutes les classes ne devraient pas mettre en œuvre clonable.


Je pense que la Javadoc que vous avez citée apporte réellement le point de l'OPS: 99% de tous les programmeurs Java penseront à l'indépendance en termes d'état d'objet, c'est-à-dire que la modification de l'état du X n'affectera pas l'état de ( le résultat d'un précédent) x.clone () . Et dans ce sens, il est très raisonnable d'implémenter clone () par renvoie ce . J'irais aussi loin que tout code s'appuyant sur la non-identité de clone () résultat est beaucoup plus susceptible d'être cassé que le code qui passe immuable singleton instances à (3ème partie?) Méthodes qui tentent de clone () , par exemple stocker l'état de l'objet.



9
votes

Quel est le but de cloner un singleton, si x.clone () == x ? Vous ne pouvez pas simplement utiliser x tout de suite.

Strictement parler, si vous voulez cloner quelque chose et appliquer x.clone () == x < / code>, le seul objet qui peut être le résultat du clone est x lui-même: xxx

qui peut être trompeur ...


Si vous concevez quelque chose et que vous êtes basé sur clone () pour la différenciation, vous le faites malho ...


1 commentaires

@Christian, votre code traite-t-il d'autres objets qui ne mettent pas en œuvre clonable ou tout faut-il être clonable?



1
votes

Votre propre réponse à votre question est la meilleure. En général, les gens attendent clone () pour redonner un autre objet. La sémantique de clonable elle-même ait plus de sens de cette façon. ("L'objet est claquant ... Oh, je dois être capable de faire des copies.") Je ne peux pas penser à une situation hors tension là où cela importe, mais c'était le sens sémantique envisagé de clonable .

Je pense que même s'ils pensaient à Singletons, ils ne l'auraient pas changé. Après tout, c'est la responsabilité du programmeur de décider de ce qui peut être cloné et ce qui ne peut pas, en ajoutant de manière sélective (et potentiellement remplacer) l'interface clonable et la plupart des programmeurs ne vont pas ajouter le Interface classique sur des singletons non plus.


1 commentaires

Pour des objets immuables, la seule différence entre la mise en œuvre réellement clone () correctement et juste retourner ce est le résultat de x.clone ()! = X , que vous n'avez aucune raison réelle de se soucier de. Si vous êtes dans une situation où vous pourriez avoir un objet mutable ou immuable, faites simplement une copie réelle. Des copies d'objets immuables sont bon marché - vous n'avez pas à recueillir le graphique de l'objet, il suffit d'attribuer les champs comme les mêmes.



0
votes

mais pour singletons au contraire, je veux x.clone () == x être vrai.

Non, ce ne serait pas un clone. Donc, pour les singletons, vous voulez ceci: xxx


5 commentaires

Oui tu devrais. Un clone devrait renvoyer un clone qui n'a pas de sens pour un singleton.


Pourquoi voudriez-vous faire clone public?


Peut-être parce que ceci est la convention lorsqu'il est remplacer clone () , voir java.sun.com/javase/6/docs/aplon/java/lang/cloneable.html .


@ Tomhawtin-tacligne: si l'on écrit un utilitaire général pour essayer de cloner un objet, chaque champ non nul doit être connu pour identifier un objet qui ne changera jamais de quelque manière que ce soit qui affecterait le champ L'état du titulaire ou bien être claçable via certains moyens. Comme il n'y a pas d'autre convention standard pour identifier les types immuables, les avoir implémenter clone de sorte qu'il renvoie ce facilite une méthode de clonage à usage général de faire ce qui devrait être fait.


@ Tomhawtin-Tackline: En outre, des singletons immuables sont souvent utilisés dans des cas où des objets mutables peuvent également être utilisés. Par exemple, code qui accepte une liste peut être attribuée une liste mutable, une liste immuable "spécialement instanciée" ou une liste immuable singleton (par exemple un vide). Si quel objet veut est un objet privé à une liste qui tiendra toujours le même contenu qu'une liste qu'elle a donnée, pouvoir appeler clone sur n'importe quelle liste qu'il reçoit - mutable ou non -Mais ne pas avoir créé un objet redondant si la liste était mutable - semblerait le comportement le plus sensible.



6
votes

mais pour singletons au contraire, je veux x.clone () == x être vrai.

vous peut vouloir, mais je pense que c'est bizarre que le code suivant briserait: xxx

(bien sûr, depuis clone () ne donne que des copies peu profondes, même une implémentation correcte de celle-ci peut entraîner des erreurs dans le code ci-dessus.)

D'autre part, je peux en quelque sorte accepter que cela aurait un sens à Les opérations de clonage à juste renvoient ce pour des objets immuables et que les Enums devraient vraiment être immuables. Maintenant, lorsque le contrat de clone () a été écrit, ils n'ont apparemment pas pensé à des immutables, ou ils ne voulaient pas de cas spécial pour un concept qui n'est pas pris en charge par la langue (c.-à-d. Imutable Types).

et donc, clone () est ce que c'est, et que vous ne pouvez pas très bien aller et changer quelque chose qui existe depuis Java 1.0. Je suis tout à fait certain que quelque part là-bas, il y a du code qui repose totalement sur clone () renvoyant un nouvel objet distinct, peut-être comme une clé pour un IdentityHashMap ou quelque chose. < / blockquote>


0 commentaires