Un clone est une copie exacte de l’original. En java, cela signifie essentiellement la possibilité de créer un objet avec un état similaire à l’objet d’origine. La méthode java clone()
fournit cette fonctionnalité.
Dans cet article, nous explorerons la plupart des aspects importants du clone Java.
Table of Contents1. What is clone?2. Java Cloneable interface and clone() method3. Shallow Copy4. Deep Copy5. Java Copy Constructors6. Deep copy with serialization7. Cloning using Apache commons8. Java clone best practices
Qu’est-ce que le clone Java ?
Le clonage consiste donc à créer la copie de l’objet original. Sa signification dans le dictionnaire est : « faire une copie identique de ».
Par défaut, le clonage java est « copie champ par champ », c’est-à-dire que la classe Objet n’a aucune idée de la structure de la classe sur laquelle la méthode clone() sera invoquée.
Ainsi, la JVM lorsqu’elle est appelée pour le clonage, fait les choses suivantes:
- Si la classe n’a que des membres de type de données primitives, une copie complètement nouvelle de l’objet sera créée et la référence à la nouvelle copie de l’objet sera renvoyée.
- Si la classe contient des membres de n’importe quel type de classe, seules les références d’objet à ces membres sont copiées et donc les références de membre dans l’objet d’origine ainsi que dans l’objet cloné font référence au même objet.
En dehors du comportement par défaut ci-dessus, vous pouvez toujours remplacer ce comportement et spécifier le vôtre. Ceci est fait en utilisant la méthode clone()
. Voyons comment cela se fait.
Interface clonable Java et méthode clone()
Chaque langage qui prend en charge le clonage d’objets a ses propres règles, tout comme java. En java, si une classe doit prendre en charge le clonage, elle doit faire les choses suivantes :
- Vous devez implémenter l’interface
Cloneable
. - Vous devez remplacer la méthode
clone()
de la classe d’objets.
En savoir plus: L’interface clonable est cassée en java
Les documents Java sur la méthode clone()
sont donnés ci-dessous (formatés et extraits).
- La première instruction garantit que l’objet cloné aura une affectation d’adresse mémoire distincte.
- La deuxième instruction suggère que les objets originaux et clonés doivent avoir le même type de classe, mais ce n’est pas obligatoire.
- La troisième instruction suggère que les objets originaux et clonés devraient être égaux en utilisant la méthode equals(), mais ce n’est pas obligatoire.
Comprenons le clone Java avec un exemple. Notre première classe est la classe Employee
avec 3 attributs – id
name
et department
.
Department
la classe a deux attributs – id
et name
.
Donc, si nous devons cloner la classe Employee, alors nous devons faire quelque chose comme ça.
Très bien, nous avons cloné avec succès l’objet Employee
. Mais, rappelez-vous que nous avons deux références au même objet et maintenant les deux vont changer l’état de l’objet dans différentes parties de l’application. Tu veux voir comment? Voyons voir.
Oups, les modifications d’objets clonés sont également visibles dans l’original. De cette façon, les objets clonés peuvent faire des ravages dans le système s’ils sont autorisés à le faire. N’importe qui peut venir cloner vos objets d’application et faire ce qu’il veut. Pouvons-nous empêcher cela??
La réponse est oui, nous pouvons. Nous pouvons empêcher cela en créant une copie profonde Java et en utilisant des constructeurs de copie. Nous en apprendrons plus tard dans cet article. Voyons d’abord ce qu’est le clonage profond et le clonage peu profond en Java.
Copie peu profonde de Java
Le clone peu profond est une ”implémentation par défaut » en Java. Dans la méthode clone
remplacée, si vous ne clonez pas tous les types d’objets (pas les primitives), vous faites une copie superficielle.
Tous les exemples ci-dessus sont de copie superficielle uniquement, car nous n’avons pas cloné l’objet Department
sur la méthode Employee
de la classe clone
. Maintenant, je vais passer à la section suivante où nous verrons le clonage profond.
Copie profonde Java
Le clone profond est le comportement souhaité dans la plupart des cas. Dans la copie profonde, nous créons un clone qui est indépendant de l’objet d’origine et apporter des modifications à l’objet cloné ne devrait pas affecter l’objet d’origine.
Voyons comment la copie profonde est créée en Java.
J’ai modifié la méthode Employee
classes clone()
et ajouté la méthode suivante clone
dans la classe Department
.
Maintenant, tester notre code de clonage donne le résultat souhaité et le nom du département ne sera pas modifié.
Ici, le changement d’état de l’objet cloné n’affecte pas l’objet d’origine.
Le clonage profond nécessite donc la satisfaction des règles suivantes –
- Pas besoin de copier séparément les primitives.
- Toutes les classes membres de la classe d’origine doivent prendre en charge le clonage et dans la méthode de clonage de la classe d’origine dans le contexte doivent appeler
super.clone()
sur toutes les classes membres. - Si une classe membre ne prend pas en charge le clonage, dans la méthode clone, il faut créer une nouvelle instance de cette classe membre et copier tous ses attributs un par un dans un nouvel objet de classe membre. Ce nouvel objet de classe membre sera défini dans l’objet cloné.
En savoir plus: Clonage profond utilisant la sérialisation en mémoire
Constructeurs de copie Java
Les constructeurs de copie sont des constructeurs spéciaux dans une classe qui prend des arguments pour son propre type de classe. Ainsi, lorsque vous transmettez une instance de classe à copy constructor, le constructeur renverra une nouvelle instance de classe avec des valeurs copiées à partir de l’instance d’argument. Il vous aide à cloner un objet avec une interface clonable.
Voyons ceci dans l’exemple:
public class PointOne {private Integer x;private Integer y;public PointOne(PointOne point){this.x = point.x;this.y = point.y;}}
Cette méthode semble simple et c’est jusqu’à ce que vient l’héritage. Lorsque vous définissez une classe en étendant au-dessus de la classe, vous devez également définir un constructeur similaire. Dans la classe enfant, vous devez copier des attributs spécifiques à l’enfant et transmettre l’argument au constructeur de la super classe. Voyons comment ?
Alors, ça va maintenant ? AUCUN. Le problème avec l’héritage est que le comportement exact n’est identifié qu’au moment de l’exécution. Donc, dans notre cas, si une classe a passé l’instance de PointTwo
dans le constructeur de PointOne
.
Dans ce cas, vous obtiendrez l’instance de PointOne
en retour où vous passerez l’instance de PointTwo
en argument. Voyons cela dans le code:
Une autre façon de créer un constructeur de copie est d’avoir des méthodes d’usine statiques. Ils prennent le type de classe en argument et créent une nouvelle instance en utilisant un autre constructeur de la classe. Ensuite, ces méthodes d’usine copient toutes les données d’état dans la nouvelle instance de classe qui vient d’être créée à l’étape précédente et renvoient cette instance mise à jour.
Copie profonde Java avec sérialisation
La sérialisation est un autre moyen facile de clonage en profondeur. Dans cette méthode, il vous suffit de sérialiser l’objet à cloner et de le désérialiser. De toute évidence, l’objet qui doit être cloné doit implémenter l’interface Serializable
.
Avant d’aller plus loin, je dois préciser que cette technique ne doit pas être utilisée à la légère.
- Tout d’abord, la sérialisation est extrêmement coûteuse. Cela pourrait facilement être cent fois plus cher que la méthode
clone()
. - Deuxièmement, tous les objets ne sont pas
Serializable
. - Troisièmement, créer une classe
Serializable
est délicat et toutes les classes ne peuvent pas être invoquées pour bien faire les choses.
En savoir plus : Un guide pour implémenter la sérialisation en Java
Java clone–SerializationUtils
Dans Apache commons, SerializationUtils
la classe a également une fonction utilitaire pour clonage profond. Si vous vous sentez intéressé, suivez leurs documents officiels.
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.7</version></dependency>
SomeObject cloned = org.apache.commons.lang.SerializationUtils.clone(someObject);
Meilleures pratiques de clonage Java
- Lorsque vous ne savez pas si vous pouvez appeler la méthode
clone()
d’une classe particulière car vous ne savez pas si elle est implémentée dans cette classe, vous pouvez vérifier en vérifiant si la classe est une instance de l’interface «Cloneable
” comme ci-dessous.if(obj1 instanceof Cloneable){ obj2 = obj1.clone();}//Dont do this. Cloneable dont have any methodsobj2 = (Cloneable)obj1.clone();
- Aucun constructeur n’est appelé sur l’objet cloné. En conséquence, il est de votre responsabilité de vous assurer que tous les membres ont été correctement installés. De plus, si vous gardez une trace du nombre d’objets dans le système en comptant l’invocation des constructeurs, vous obtenez un nouvel emplacement supplémentaire pour incrémenter le compteur.
J’espère que ce post a été un rappel pour vous et vous aidera à obtenir plus d’informations sur la méthode de clone Java 8 et son utilisation correcte. Cela aidera également à répondre aux questions d’entrevue de clonage Java.
Bon apprentissage!!