Copie en profondeur, la copie superficielle, clone
J'ai besoin de précisions sur les différences entre la copie, la copie superficielle, et clone en Java
- Ressemble à la fois des devoirs à faire à la question et quelque chose qui a des milliers d'articles en ligne sur elle. Comme ceci.
- Pouvez-vous être un peu plus précis? Est-il un ensemble de méthodes ou de bibliothèques que vous avez à l'esprit pour l'utiliser pendant un certain problème?
Vous devez vous connecter pour publier un commentaire.
Malheureusement, "copie", "copie" et "clone" sont tous assez mal définies.
Dans le Java contexte, nous devons d'abord faire une distinction entre "la copie d'un valeur" et "copie d'un objet".
En bref, une affectation d'une référence à une variable dont le type est un type de référence est "la copie d'une valeur" où la valeur est la référence de l'objet. Pour copier un objet, quelque chose doit utiliser
new
, soit de manière explicite ou sous le capot.Maintenant pour "superficielle" et "profonde" de la copie d'objets. Peu profonde de la copie signifie généralement la copie d'un seul niveau d'un objet, tandis que la profondeur de la copie signifie généralement la copie plus d'un niveau. Le problème est de décider ce que nous entendons par niveau. Considérez ceci:
L'interprétation normale est qu'un "peu profonde" copie de
eg1
serait une nouvelleExample
objet dontfoo
est égal à 1 et dontbar
champ désigne le même tableau que dans l'original; par exemple,L'interprétation normale d'une "profonde" copie de
eg1
serait une nouvelleExample
objet dontfoo
est égal à 1 et dontbar
champ fait référence à un copie de le tableau d'origine; par exemple,(Les gens à venir à partir d'un C /C++ fond pourrait dire qu'une référence de produit de la cession d'une copie. Cependant, ce n'est pas ce que nous avons l'habitude de dire à faible profondeur, la copie dans le Java contexte ...)
Deux plus de questions ou de zones d'incertitude existent:
Comment est-elle profonde? Faut-il s'arrêter à deux niveaux? Les trois niveaux? Signifie-t-il de tout le graphe d'objets connectés?
Qu'en est encapsulé types de données, par exemple une Chaîne de caractères? Une Chaîne n'est pas juste un objet. En fait, c'est un "objet" avec certains champs scalaires, et une référence à un tableau de caractères. Toutefois, le tableau de caractères est complètement masqué par l'API. Donc, lorsque nous parlons de la copie d'une Chaîne, est-il judicieux de l'appeler un "peu profonde" copie ou d'un "profond" copie? Ou devrions-nous l'appeler une copie?
Enfin, clone. Clone est une méthode qui existe sur toutes les classes (et tableaux) qui est généralement pensé pour produire une copie de l'objet cible. Cependant:
La spécification de cette méthode a choisi délibérément de ne pas dire si c'est un peu profonde ou profonde copie (en supposant que c'est une distinction importante).
En fait, le cahier des charges n'a pas spécifiquement d'état que le clone produit un nouvel objet.
Voici ce que la javadoc dit:
Noter que c'est en disant qu'à un extrême, le clone pourrait être l'objet cible, et à l'autre extrême, le clone peut pas égale à l'original. Et cela suppose que le clone est même prise en charge.
En bref, clone potentiellement signifie quelque chose de différent pour chaque classe Java.
Certaines personnes soutiennent (comme @supercat ne dans les commentaires) que le Java
clone()
méthode est cassé. Mais je pense que la bonne conclusion est que le notion de clone est cassée dans le contexte de l'OO. Autant que je sache, il est impossible de développer un modèle unifié de clonage qui est cohérente et utilisable dans tous les types d'objet.x.clone().equals(x)
devrait être prévue pour être vrai me semble étrange. Le seul sens pourequals
je pense, qui serait compatible pour tous les types d'objet serait d'équivalence, et en aucun cas d'une mutable type devrait être considérée comme équivalente à une autre instance. Si un objet est immuable, il n'y a pas de raison pour le clone, et si un objet est mutable, il ne devrait pas être l'équivalent de son clone.List<T>
est la suite de l'article les références qui y sont contenues; donc un bon clone deList<T>
de classe de typeT
devrait être prévue pour les références aux mêmes éléments que la liste originale. Il peut être utile d'avoir unEncapsulatedItemList<T>
, qui serait défini comme l'encapsulation de l'mutable état des éléments qui y sont, et dontClone
méthode serait d'utiliser unCloner<T>
fourni à la construction de dupliquer les éléments.equals
, je pense que Java est gros défaut est que de nombreuses collections exiger que les types de la remplacer pour signifier autre chose que de l'équivalence; en .net, le constructeur pour unDictionary<TKey,TValue>
peut accepter unIEqualityComparer<TKey>
qui peut utiliser quelque chose de beaucoup plus lâche qu'objet d'équivalence, même siTKey
's de remplacerEquals(Object)
ne pas; je ne pense pas qu'une telle fonction existe en Java. D'autre part, .net met en avant l'idée que==
et.Equals
devrait généralement la même, malgré le fait que==
ne peut pas définir une bonne relation d'équivalence.!=
est réservé pour vérifier si les deux cas sont les mêmes, alors que.equals()
est souvent réservé pour la vérification de la soi-disant "logique de l'égalité" (vérifier si l'état de deux cas est le même.) Par exemple, les gens qui sont l'écriture scientifique ou de logiciels financiers pourrait vouloir de deux instances différentes pour être considérées comme égales si elles ont le même état.Le terme "clone" est ambigu (bien que la classe Java bibliothèque comprend une Clonable interface) et peut se référer à une copie ou une copie superficielle. Fond peu profond copies ne sont pas spécifiquement liées à Java, mais sont un concept général concernant la création d'une copie d'un objet, et se réfère à la façon dont les membres d'un objet sont également copiés.
Comme un exemple, disons que vous avez une personne de la classe:
Comment cloner des objets de cette classe? Si vous effectuez une copie, vous pouvez copier le nom et le mettre une référence à
emailAddresses
dans le nouvel objet. Mais si vous avez modifié le contenu de laemailAddresses
liste, vous pouvez modifier la liste en deux exemplaires (puisque c'est la façon dont les références de l'objet de travail).Une copie en profondeur signifierait que vous récursive copie à chaque membre, de sorte que vous devez créer un nouveau
List
pour la nouvellePerson
, puis copiez le contenu de l'ancien vers le nouvel objet.Bien que l'exemple ci-dessus est trivial, les différences entre les profondes et peu profondes des copies sont importantes et ont un impact majeur sur n'importe quelle application, surtout si vous essayez de concevoir un générique de la méthode clone à l'avance, sans savoir comment quelqu'un pourrait l'utiliser plus tard. Il ya des moments où vous avez besoin profonds ou de la sémantique, ou de certains hybrides où vous copie en profondeur certains membres, mais pas d'autres.
o.clone() == o
peut être vrai; voir ma réponse.Les termes de "copie" et "copie" sont un peu vague; je vous suggérons d'utiliser les termes "memberwise clone" et ce que j'appellerais une "sémantique clone". Un "memberwise clone" d'un objet est un nouvel objet, du même type à l'exécution que l'original, pour chaque champ, le système exécute efficacement "newObject.champ = oldObject.champ". L'Objet de base.Clone() effectue une memberwise clone; memberwise le clonage est généralement le droit point de départ pour le clonage d'un objet, mais dans la plupart des cas, une correction de travail" seront requis à la suite d'un memberwise clone. Dans de nombreux cas, la tentative d'utilisation d'un objet produit par memberwise clone sans effectuant d'abord la nécessaire correction sera la cause de mauvaises choses se produisent, y compris la corruption de l'objet qui a été cloné et éventuellement d'autres objets. Certaines personnes utilisent le terme "shallow clonage" pour désigner memberwise clonage, mais ce n'est pas la seule utilisation du terme.
Une sémantique "clone" est un objet qui contient les mêmes données que la version originale, du point de vue du type. Pour examiner, considérer un BigList qui contient un Tableau>, et un nombre. Une sémantique au niveau de clone d'un tel objet serait d'effectuer une memberwise clone, puis remplacez le Tableau> avec un nouveau tableau, créer de nouveaux tableaux imbriqués, et de copier tous les T de l'original de tableaux pour les nouveaux. Il ne serait pas tenter toute sorte de profond-clonage de la T eux-mêmes. Ironiquement, certaines personnes se réfèrent à la de clonage "shallow clonage", tandis que d'autres l'appellent "profonde clonage". Pas exactement la terminologie utile.
Alors qu'il y a des cas où vraiment profond de clonage (de façon récursive la copie de tous types mutables) est utile, elle doit être effectuée par des types dont les constituants sont conçus pour une telle architecture. Dans de nombreux cas, vraiment profond de clonage est excessive, et il peut interférer avec les situations où ce qui est nécessaire est en fait un objet dont le contenu visible consultez les mêmes objets que l'autre (c'est à dire d'une sémantique de la copie de niveau). Dans le cas où le contenu visible d'un objet sont récursivement dérivée à partir d'autres objets, une sémantique au niveau de clone impliquerait une récursif profonde clone, mais dans le cas où le contenu visible sont juste quelques-uns de type générique, le code ne devrait pas aveuglément profonde clone tout ce qui ressemble, il peut éventuellement être profond-clone-mesure.