Java Astuce 76 Une alternative à la profondeur technique de copie, JavaWorld

La mise en œuvre d'une copie en profondeur d'un objet peut être une expérience d'apprentissage - vous apprendre que vous ne voulez pas le faire! Si l'objet en question fait référence à d'autres objets complexes, ce qui se réfèrent à d'autres, cette tâche peut être ardue en effet. Traditionnellement, chaque classe de l'objet doit être inspecté et modifié individuellement pour implémenter l'interface Cloneable et remplacer la méthode clone () afin de faire une copie profonde de lui-même, ainsi que ses objets contenus. Cet article décrit une technique simple à utiliser à la place de ce temps copie en profondeur conventionnelle.

Le concept de copie en profondeur

Pour comprendre ce qu'est une copie en profondeur est, nous allons d'abord examiner le concept de copie peu profonde.

Figure 1. L'état initial de obj1

Si une copie superficielle est effectuée sur obj1. alors il est copié, mais ses objets contenus ne sont pas, comme le montre la figure 2.

Figure 2. Après une copie superficielle de obj1

Une copie complète se produit lorsqu'un objet est copié en même temps que l'objet auquel il se réfère. La figure 3 montre obj1 après une copie en profondeur a été réalisée sur elle. Non seulement a été copié obj1, mais les objets contenus dans ce document ont été copiés aussi.

Figure 3. Après une copie profonde de obj1

Si l'un de ces objets contenus eux-mêmes contiennent des objets, puis, dans une copie en profondeur, sont copiés ces objets ainsi, et ainsi de suite jusqu'à ce que le graphe entier est parcouru et copié. Chaque objet est responsable de lui-même le clonage via sa méthode clone (). La méthode clone par défaut (), héritée de l'objet. fait une copie superficielle de l'objet. Pour obtenir une copie en profondeur, la logique supplémentaire, il faut ajouter que les appels explicitement tous les contenus des méthodes clone (), qui appellent à leur tour leurs objets contenus des objets clone () méthodes, et ainsi de suite. Obtenir ce correct peut être difficile et prend du temps, et est rarement amusant. Pour la méthode choses encore plus compliquées, si un objet ne peut pas être modifié directement et son clone () produit une copie peu profonde, la classe doit être étendue, la méthode clone () redéfinie, et cette nouvelle classe à la place de la vieux. (Par exemple, vecteur ne contient pas la logique nécessaire pour une copie en profondeur.) Et si vous voulez écrire du code qui diffère jusqu'à l'exécution de la question de savoir si de faire une copie profonde ou peu profonde d'un objet, vous êtes dans un plus situation compliquée. Dans ce cas, il doit y avoir deux fonctions de copie pour chaque objet: un pour une copie en profondeur et une pour une faible profondeur. Enfin, même si l'objet profond copié contient plusieurs références à un autre objet, ce dernier objet doit encore que copier une fois. Cela empêche la prolifération des objets, et se rend la situation particulière dans laquelle une référence circulaire produit une boucle infinie de copies.

sérialisation

Profonde copie à l'aide sérialisation

Les étapes pour faire une copie en profondeur à l'aide sérialisation sont les suivantes:

Assurez-vous que toutes les classes dans le graphique de l'objet sont sérialisables.

Créer des courants d'entrée et de sortie.

Utiliser les courants d'entrée et de sortie pour créer l'entrée de l'objet et de l'objet flux de sortie.

Passez l'objet que vous souhaitez copier dans le flux de sortie d'objet.

  • Lire le nouvel objet à partir du flux d'entrée d'objet et de le jeter à la classe de l'objet que vous avez envoyé.
  • Un moyen facile de savoir si vous avez des cours dans le graphe non sérialisable d'un objet est de supposer qu'ils sont tous sérializable et méthode deepCopy () s » exécuter ObjectCloner sur elle. S'il y a un objet dont la classe est pas sérialisable, alors java.io.NotSerializableException sera jeté, vous dire quelle classe a causé le problème.

    Un exemple de mise en œuvre rapide est illustré ci-dessous. Il crée un objet simple, v1. qui est un vecteur qui contient un point. Cet objet est ensuite imprimé pour afficher son contenu. L'objet original, v1. est ensuite copié vers un nouvel objet, vNew. qui est imprimé pour montrer qu'il contient la même valeur que v1. Ensuite, le contenu de v1 sont modifiés, et enfin les deux v1 et vNew sont imprimées de sorte que leurs valeurs peuvent être comparées.

    Pour appeler la copie profonde (ligne A), exécutez java.exe Driver1 profonde. Une fois la copie profonde fonctionne, nous obtenons l'impression suivante:

    Cela montre que lorsque le point d'origine. p1. a été changé, le nouveau point créé à la suite de la copie profonde n'a pas été affectée, puisque le graphe entier a été copié. A titre de comparaison, invoquer la copie superficielle (ligne B) en exécutant java.exe peu profonde Driver1. Lorsque la copie superficielle fonctionne, on a l'impression suivante:

    Cela montre que lorsque le point d'origine a été changé, le nouveau point a été changé. Cela est dû au fait que la copie superficielle fait des copies que des références, et non des objets auxquels ils se réfèrent. Ceci est un exemple très simple, mais je pense qu'il illustre la, euh, le point.

    les questions de mise en œuvre

    Maintenant que je l'ai prêché sur toutes les vertus de la copie en profondeur à l'aide sérialisation, regardons certaines choses à surveiller.

    Le premier cas problématique est une classe qui ne sont pas sérialisable et qui ne peut être modifié. Cela pourrait se produire, par exemple, si vous utilisez une classe tiers qui ne vient pas avec le code source. Dans ce cas, vous pouvez l'étendre, faire la classe élargie mettre en œuvre Serializable. ajouter tout (ou tous) les constructeurs nécessaires qui appellent juste le superconstructeur associé, et utiliser cette nouvelle classe partout où vous avez fait l'ancien (voici un exemple).

    Milliseconde à copie en profondeur un graphique simple de classe n fois

    Conclusion

    La mise en œuvre copie en profondeur d'un objet graphique complexe peut être une tâche difficile. La technique ci-dessus est une alternative simple à la procédure classique de la méthode clone d'écraser () pour chaque objet dans le graphique.

    Dave Miller est un architecte principal du cabinet d'experts-conseils Javelin Technology, où il travaille sur Java et des applications Internet. Il a travaillé pour des sociétés telles que Hughes, IBM, Nortel, et MCIWorldcom sur des projets orientés objet, et a travaillé exclusivement avec Java pour les trois dernières années.

    En savoir plus sur ce sujet

    Suivez tout de JavaWorld