Java Language
Kloning av objekt
Sök…
Anmärkningar
Kloning kan vara svårt, särskilt när objektets fält innehåller andra objekt. Det finns situationer där du vill utföra en djup kopia , istället för att bara kopiera fältvärdena (dvs. referenser till andra objekt).
Den nedersta raden är klon är trasig , och du bör tänka två gånger innan du implementerar det Cloneable
gränssnittet och åsidosätter clone
. clone
deklareras i Object
och inte i gränssnittet Cloneable
, så Cloneable
misslyckas med att fungera som ett gränssnitt eftersom det saknar en offentlig clone
. Resultatet är att kontraktet för användning av clone
är tunt dokumenterat och svagt verkställt. Till exempel, en klass som åsidosätter clone
förlitar sig ibland på alla sina överordnade klasser som också åsidosätter clone
. De tvingas inte göra det, och om de inte gör det kan din kod kasta undantag.
En mycket bättre lösning för att tillhandahålla kloningsfunktionalitet är att tillhandahålla en kopieringskonstruktör eller kopieringsfabrik . Se Joshua Blochs effektiva Java- punkt 11: Överväga klon på ett klokt sätt.
Kloning med en kopieringskonstruktör
Ett enkelt sätt att klona ett objekt är genom att implementera en kopieringskonstruktör.
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
Kloning genom att implementera Clonable interface
Kloning av ett objekt genom att implementera Cloneable- gränssnittet.
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
Kloning utför en ytlig kopia
Standardbeteende vid kloning av ett objekt är att utföra en ytlig kopia av objektets fält. I så fall har både det ursprungliga objektet och det klonade objektet referenser till samma objekt.
Detta exempel visar det beteendet.
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));
}
Kloning utför en djup kopia
För att kopiera kapslade objekt måste en djup kopia utföras, som visas i det här exemplet.
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));
}
Kloning med en kopieringsfabrik
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)
}
}