Je me demande s'il existe une méthode recommandée pour effectuer un clonage / copie en profondeur d'une instance en java.
J'ai 3 solutions en tête, mais j'en ai raté quelques-unes, et j'aimerais avoir votre avis
modifier: inclure la proposition de Bohzo et affiner la question: il s'agit plus de clonage profond que de clonage superficiel.
Fais le toi-même:
coder le clone à la main les propriétés après les propriétés et vérifier que les instances mutables sont également clonées.
pro:
- contrôle de ce qui sera effectué
- exécution rapide
contre:
- fastidieux à écrire et à maintenir
- sujet aux bogues (échec copier / coller, propriété manquante, propriété mutable réaffectée)
Utilisez la réflexion:
Avec vos propres outils de réflexion ou avec un assistant externe (comme jakarta common-beans), il est facile d'écrire une méthode de copie générique qui fera le travail en une seule ligne.
pro:
- facile à écrire
- pas de maintenance
contre:
- moins de contrôle sur ce qui se passe
- sujet aux bugs avec objet mutable si l'outil de réflexion ne clone pas trop les sous-objets
- exécution plus lente
Utilisez le cadre de clonage:
Utilisez un framework qui le fait pour vous, comme:
commons-lang SerializationUtils
Java Deep Cloning Library
Dozer
Kryo
pro:
- identique à la réflexion
- plus de contrôle sur ce qui sera exactement cloné.
inconvénients:
- chaque instance mutable est entièrement clonée, même à la fin de la hiérarchie
- peut être très lente à exécuter
Utiliser l'instrumentation bytecode pour écrire un clone au moment de l'exécution
javassit , BCEL ou cglib peuvent être utilisés pour générer un cloneur dédié aussi vite qu'une écriture manuelle. Quelqu'un connaît une bibliothèque utilisant l'un de ces outils à cette fin?
Qu'est-ce que j'ai manqué ici?
Lequel recommanderiez-vous?
Merci.
Réponses:
Pour le clonage profond (clone la totalité de la hiérarchie d'objets):
commons-lang SerializationUtils - en utilisant la sérialisation - si toutes les classes sont sous votre contrôle et que vous pouvez forcer l'implémentation
Serializable
.Java Deep Cloning Library - en utilisant la réflexion - dans les cas où les classes ou les objets que vous souhaitez cloner sont hors de votre contrôle (une bibliothèque tierce) et que vous ne pouvez pas les faire implémenter
Serializable
, ou dans les cas où vous ne souhaitez pas implémenterSerializable
.Pour le clonage superficiel (ne clone que les propriétés de premier niveau):
commons-beanutils BeanUtils - dans la plupart des cas.
Spring BeanUtils - si vous utilisez déjà spring et que vous avez donc cet utilitaire sur le chemin de classe .
J'ai délibérément omis l'option "do-it-yourself" - les API ci-dessus fournissent un bon contrôle sur ce qu'il faut et ne pas cloner (par exemple en utilisant
transient
, ouString[] ignoreProperties
), donc réinventer la roue n'est pas préférable.la source
Le livre de Joshua Bloch a un chapitre entier intitulé "Point 10: Ignorer le clone de manière judiciaire" dans lequel il explique pourquoi le remplacement du clone est pour la plupart une mauvaise idée parce que la spécification Java crée de nombreux problèmes.
Il propose quelques alternatives:
Utilisez un modèle de fabrique à la place d'un constructeur:
Utilisez un constructeur de copie:
Toutes les classes de collection en Java supportent le constructeur de copie (par exemple new ArrayList (l);)
la source
Copyable
interface contenant unegetCopy()
méthode. Utilisez simplement le modèle de prototype manuellement.newInstance()
méthode et leYum
constructeur feraient une copie profonde ou une copie superficielle?Depuis la version 2.07, Kryo prend en charge le clonage superficiel / profond :
Kryo est rapide, sur leur page, vous trouverez une liste des entreprises qui l'utilisent en production.
la source
Utilisez XStream toXML / fromXML en mémoire. Extrêmement rapide et existe depuis longtemps et va fort. Les objets n'ont pas besoin d'être sérialisables et vous n'avez pas de réflexion d'utilisation (bien que XStream le fasse). XStream peut discerner les variables qui pointent vers le même objet et ne pas faire accidentellement deux copies complètes de l'instance. Beaucoup de détails comme celui-là ont été élaborés au fil des ans. Je l'utilise depuis un certain nombre d'années et c'est un incontournable. C'est à peu près aussi facile à utiliser que vous pouvez l'imaginer.
ou
Cloner,
Plus succinctement:
la source
Pour les objets compliqués et lorsque les performances ne sont pas significatives, j'utilise gson pour sérialiser l'objet en texte json, puis désérialise le texte pour obtenir un nouvel objet.
gson qui basé sur la réflexion fonctionnera dans la plupart des cas, sauf que les
transient
champs ne seront pas copiés et les objets avec une référence circulaire avec causeStackOverflowError
.la source
Dépend.
Pour la vitesse, utilisez le bricolage. Pour pare-balles, utilisez la réflexion.
BTW, la sérialisation n'est pas la même chose que refl, car certains objets peuvent fournir des méthodes de sérialisation écrasées (readObject / writeObject) et ils peuvent être bogués
la source
Je recommanderais la méthode DIY qui, combinée à une bonne méthode hashCode () et equals (), devrait être facile à prouver dans un test unitaire.
la source
Je suggère de remplacer Object.clone (), d'appeler d'abord super.clone () et d'appeler ref = ref.clone () sur toutes les références que vous souhaitez copier en profondeur. C'est plus ou moins une approche Do it yourself mais nécessite un peu moins de codage.
la source
Pour le clonage profond, implémentez Serializable sur chaque classe que vous souhaitez cloner comme ceci
Et puis utilisez cette fonction:
comme ça:
Obj newObject = (Obj)deepClone(oldObject);
la source