Java Language
Клонирование объектов
Поиск…
замечания
Клонирование может быть сложным, особенно когда в полях объекта хранятся другие объекты. Бывают ситуации, когда вы хотите выполнить глубокую копию вместо того, чтобы копировать только значения поля (т.е. ссылки на другие объекты).
Нижняя строка - это клон , и вам следует подумать дважды, прежде чем внедрять интерфейс Cloneable
и переопределять метод clone
. Метод clone
объявлен в классе Object
а не в интерфейсе Cloneable
, поэтому Cloneable
не может функционировать как интерфейс, потому что ему не хватает общедоступного метода clone
. В результате контракт на использование clone
тонко документирован и слабо соблюдается. Например, класс, который переопределяет clone
иногда полагается на все его родительские классы, также перекрывающие clone
. Они не применяются для этого, и если они не делают ваш код, вы можете исключать исключения.
Лучшим решением для обеспечения функциональности клонирования является создание конструктора копирования или фабрики копирования . См . Эффективный Java Joshua Bloch. Пункт 11: разумно переверните клон.
Клонирование с использованием конструктора копирования
Простым способом клонирования объекта является реализация конструктора копирования.
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
Клонирование путем реализации интерфейса Clonable
Клонирование объекта путем реализации интерфейса 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
Клонирование выполнения мелкой копии
Поведение по умолчанию при клонировании объекта заключается в выполнении мелкой копии полей объекта. В этом случае как исходный объект, так и клонированный объект содержат ссылки на одни и те же объекты.
Этот пример показывает это поведение.
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));
}
Клонирование, выполняющее глубокую копию
Для копирования вложенных объектов необходимо выполнить глубокую копию , как показано в этом примере.
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));
}
Клонирование с использованием фабрики копирования
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)
}
}