Je cherchais des tutoriels expliquant Java Cloneable
, mais je n'ai pas obtenu de bons liens, et Stack Overflow devient de toute façon un choix plus évident.
J'aimerais savoir ce qui suit:
Cloneable
signifie que nous pouvons avoir un clone ou une copie d'objets, en implémentant l'Cloneable
interface. Quels sont les avantages et les inconvénients de faire cela?- Comment se produit le clonage récursif si l'objet est un objet composite?
Réponses:
La première chose que vous devez savoir
Cloneable
est de ne pas l'utiliser.Il est très difficile de mettre en œuvre le clonage avec le
Cloneable
droit, et l'effort n'en vaut pas la peine.Au lieu de cela, utilisez d'autres options, comme apache-commons
SerializationUtils
(deep-clone) ouBeanUtils
(shallow-clone), ou utilisez simplement un constructeur de copie.Voir ici le point de vue de Josh Bloch sur le clonage avec
Cloneable
, ce qui explique les nombreux inconvénients de l'approche. ( Joshua Bloch était un employé de Sun et a dirigé le développement de nombreuses fonctionnalités Java.)la source
static
méthodes dans les interfaces, alors fournissez simplement unstatic WhatEverTheInterface copy(WhatEverTheInterface initial)
? mais je me demande ce que cela vous donne, puisque vous copiez les champs d'un objet lors du clonage, mais une interface ne définit que des méthodes. soin d'expliquer?Cloneable lui-même n'est malheureusement qu'une interface de marqueur, c'est-à-dire qu'il ne définit pas la méthode clone ().
Cela change le comportement de la méthode Object.clone () protégée, qui lèvera une CloneNotSupportedException pour les classes qui n'implémentent pas Cloneable, et effectuera une copie superficielle par membre pour les classes qui le font.
Même si c'est le comportement que vous recherchez, vous devrez toujours implémenter votre propre méthode clone () pour la rendre publique.
Lors de l'implémentation de votre propre clone (), l'idée est de commencer par l'objet créé par super.clone (), qui est garanti d'être de la classe correcte, puis de faire toute population supplémentaire de champs au cas où une copie superficielle ne serait pas ce que tu veux. L'appel d'un constructeur depuis clone () serait problématique car cela briserait l'héritage au cas où une sous-classe voudrait ajouter sa propre logique clonable supplémentaire; s'il appelait super.clone (), il obtiendrait un objet de la mauvaise classe dans ce cas.
Cette approche contourne toute logique qui peut être définie dans vos constructeurs, ce qui pourrait potentiellement être problématique.
Un autre problème est que toutes les sous-classes qui oublient de remplacer clone () hériteront automatiquement de la copie superficielle par défaut, ce qui n'est probablement pas ce que vous voulez en cas d'état mutable (qui sera maintenant partagé entre la source et la copie).
La plupart des développeurs n'utilisent pas Cloneable pour ces raisons et implémentent simplement un constructeur de copie à la place.
Pour plus d'informations et les pièges potentiels de Cloneable, je recommande vivement le livre Effective Java de Joshua Bloch
la source
Alors, utilisez Cloneable judicieusement. Cela ne vous donne pas suffisamment d'avantages par rapport aux efforts dont vous avez besoin pour tout faire correctement.
la source
Le clonage est un paradigme de programmation de base. Le fait que Java l'ait mal implémenté à bien des égards ne diminue en rien le besoin de clonage. Et, il est facile de mettre en œuvre le clonage qui fonctionnera comme vous le souhaitez, peu profond, profond, mixte, peu importe. Vous pouvez même utiliser le nom clone pour la fonction et ne pas implémenter Cloneable si vous le souhaitez.
Supposons que j'ai des classes A, B et C, où B et C sont dérivés de A. Si j'ai une liste d'objets de type A comme ceci:
Maintenant, cette liste peut contenir des objets de type A, B ou C. Vous ne savez pas de quel type sont les objets. Donc, vous ne pouvez pas copier la liste comme ceci:
Si l'objet est en fait de type B ou C, vous n'obtiendrez pas la bonne copie. Et si A était abstrait? Maintenant, certaines personnes ont suggéré ceci:
C'est une très, très mauvaise idée. Que faire si vous ajoutez un nouveau type dérivé? Que faire si B ou C sont dans un autre package et que vous n'y avez pas accès dans cette classe?
Voici ce que vous aimeriez faire:
De nombreuses personnes ont expliqué pourquoi l'implémentation Java de base du clone était problématique. Mais, il est facilement surmonté de cette façon:
En classe A:
En classe B:
En classe C:
Je n'implémente pas Cloneable, en utilisant simplement le même nom de fonction. Si vous n'aimez pas ça, donnez-lui un autre nom.
la source
A) Il n'y a pas beaucoup d'avantages du clone par rapport à un constructeur de copie. Le plus important est probablement la possibilité de créer un nouvel objet du même type dynamique (en supposant que le type déclaré est clonable et possède une méthode de clonage public).
B) Le clone par défaut crée une copie superficielle, et elle restera une copie superficielle à moins que votre implémentation de clone ne change cela. Cela peut être difficile, surtout si votre classe a des champs finaux
Bozho a raison, le clone peut être difficile à obtenir. Un constructeur / usine de copie répondra à la plupart des besoins.
la source
Quels sont les inconvénients de Cloneable?
Le clonage est très dangereux si l'objet que vous copiez a une composition.Vous devez penser aux effets secondaires possibles ci-dessous dans ce cas, car le clone crée une copie superficielle:
Supposons que vous ayez un objet pour gérer les manipulations liées à la base de données. Disons que cet objet a un
Connection
objet comme l'une des propriétés.Alors , quand quelqu'un crée clone de
originalObject
l'objet créé, nous allons direcloneObject
. IcioriginalObject
etcloneObject
maintenez la même référence pourConnection
object.Disons
originalObject
ferme l'Connection
objet, donc maintenant lecloneObject
ne fonctionnera pas parce que l'connection
objet a été partagé entre eux et il a été effectivement fermé par leoriginalObject
.Un problème similaire peut se produire si vous voulez cloner un objet qui a IOStream comme propriété.
Comment se produit le clonage récursif si l'objet est un objet composite?
Cloneable effectue une copie superficielle. Cela signifie que les données de l'objet original et de l'objet clone pointeront vers la même référence / mémoire. au contraire dans le cas d'une copie profonde, les données de la mémoire de l'objet original sont copiées dans la mémoire de l'objet clone.
la source
Cloneable
n'effectue pas de copie,Object.clone
fait. "Les données de la mémoire de l'objet original sont copiées dans la mémoire de l'objet clone" est précisément ce queObject.clone
fait. Vous devez parler de la mémoire des objets référencés pour décrire la copie profonde.