Java Language
Clonage d'objets
Recherche…
Remarques
Le clonage peut être délicat, en particulier lorsque les champs de l'objet contiennent d'autres objets. Il existe des situations où vous souhaitez effectuer une copie complète , au lieu de copier uniquement les valeurs de champ (c.-à-d. Les références aux autres objets).
La ligne du bas est clone est cassé , et vous devriez réfléchir à deux fois avant d'implémenter l'interface Cloneable
et de Cloneable
la méthode de clone
. Le clone
méthode est déclarée dans l' Object
classe et non dans la Cloneable
interface, donc Cloneable
ne fonctionne pas comme une interface , car il ne dispose pas d' un public clone
méthode. Le résultat est que le contrat d'utilisation du clone
est peu documenté et faiblement appliqué. Par exemple, une classe qui remplace le clone
s'appuie parfois sur toutes ses classes parentes qui ont également la priorité sur le clone
. Ils ne sont pas obligés de le faire, et s’ils ne le font pas, votre code peut générer des exceptions.
Une solution bien meilleure pour fournir une fonctionnalité de clonage consiste à fournir un constructeur de copie ou une fabrique de copies . Reportez-vous à l' article 11 de Java efficace de Joshua Bloch : remplacer judicieusement le clone.
Clonage à l'aide d'un constructeur de copie
Un moyen simple de cloner un objet consiste à implémenter un constructeur de copie.
public class Sheep {
private String name;
private int weight;
public Sheep(String name, int weight) {
this.name = name;
this.weight = weight;
}
// copy constructor
// copies the fields of other into the new object
public Sheep(Sheep other) {
this.name = other.name;
this.weight = other.weight;
}
}
// create a sheep
Sheep sheep = new Sheep("Dolly", 20);
// clone the sheep
Sheep dolly = new Sheep(sheep); // dolly.name is "Dolly" and dolly.weight is 20
Clonage en implémentant l'interface Clonable
Clonage d'un objet en implémentant l'interface Cloneable .
public class Sheep implements Cloneable {
private String name;
private int weight;
public Sheep(String name, int weight) {
this.name = name;
this.weight = weight;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// create a sheep
Sheep sheep = new Sheep("Dolly", 20);
// clone the sheep
Sheep dolly = (Sheep) sheep.clone(); // dolly.name is "Dolly" and dolly.weight is 20
Cloner en effectuant une copie superficielle
Le comportement par défaut lors du clonage d'un objet consiste à effectuer une copie superficielle des champs de l'objet. Dans ce cas, l'objet d'origine et l'objet cloné contiennent des références aux mêmes objets.
Cet exemple montre ce comportement.
import java.util.List;
public class Sheep implements Cloneable {
private String name;
private int weight;
private List<Sheep> children;
public Sheep(String name, int weight) {
this.name = name;
this.weight = weight;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public List<Sheep> getChildren() {
return children;
}
public void setChildren(List<Sheep> children) {
this.children = children;
}
}
import java.util.Arrays;
import java.util.List;
// create a sheep
Sheep sheep = new Sheep("Dolly", 20);
// create children
Sheep child1 = new Sheep("Child1", 4);
Sheep child2 = new Sheep("Child2", 5);
sheep.setChildren(Arrays.asList(child1, child2));
// clone the sheep
Sheep dolly = (Sheep) sheep.clone();
List<Sheep> sheepChildren = sheep.getChildren();
List<Sheep> dollysChildren = dolly.getChildren();
for (int i = 0; i < sheepChildren.size(); i++) {
// prints true, both arrays contain the same objects
System.out.println(sheepChildren.get(i) == dollysChildren.get(i));
}
Cloner en effectuant une copie en profondeur
Pour copier des objets imbriqués, une copie en profondeur doit être effectuée, comme illustré dans cet exemple.
import java.util.ArrayList;
import java.util.List;
public class Sheep implements Cloneable {
private String name;
private int weight;
private List<Sheep> children;
public Sheep(String name, int weight) {
this.name = name;
this.weight = weight;
}
@Override
public Object clone() throws CloneNotSupportedException {
Sheep clone = (Sheep) super.clone();
if (children != null) {
// make a deep copy of the children
List<Sheep> cloneChildren = new ArrayList<>(children.size());
for (Sheep child : children) {
cloneChildren.add((Sheep) child.clone());
}
clone.setChildren(cloneChildren);
}
return clone;
}
public List<Sheep> getChildren() {
return children;
}
public void setChildren(List<Sheep> children) {
this.children = children;
}
}
import java.util.Arrays;
import java.util.List;
// create a sheep
Sheep sheep = new Sheep("Dolly", 20);
// create children
Sheep child1 = new Sheep("Child1", 4);
Sheep child2 = new Sheep("Child2", 5);
sheep.setChildren(Arrays.asList(child1, child2));
// clone the sheep
Sheep dolly = (Sheep) sheep.clone();
List<Sheep> sheepChildren = sheep.getChildren();
List<Sheep> dollysChildren = dolly.getChildren();
for (int i = 0; i < sheepChildren.size(); i++) {
// prints false, both arrays contain copies of the objects inside
System.out.println(sheepChildren.get(i) == dollysChildren.get(i));
}
Clonage à l'aide d'une fabrique de copies
public class Sheep {
private String name;
private int weight;
public Sheep(String name, int weight) {
this.name = name;
this.weight = weight;
}
public static Sheep newInstance(Sheep other);
return new Sheep(other.name, other.weight)
}
}