Java Language
Clonación de objetos
Buscar..
Observaciones
La clonación puede ser complicada, especialmente cuando los campos del objeto contienen otros objetos. Hay situaciones en las que desea realizar una copia profunda , en lugar de copiar solo los valores de campo (es decir, referencias a los otros objetos).
La conclusión es que la copia está rota , y debe pensarlo dos veces antes de implementar la interfaz Cloneable
y anular el método de clone
. El método de clone
se declara en la clase Object
y no en la interfaz Cloneable
, por lo que Cloneable
no funciona como interfaz porque carece de un método de clone
público. El resultado es que el contrato para usar el clone
está escasamente documentado y se aplica de manera débil. Por ejemplo, una clase que anula la clone
veces depende de todas sus clases primarias y también anula la clone
. No están obligados a hacerlo, y si no lo hacen, su código puede generar excepciones.
Una solución mucho mejor para proporcionar funcionalidad de clonación es proporcionar un constructor de copias o una fábrica de copias . Consulte el ítem 11 de Java efectivo de Joshua Bloch : Sobrescriba el clon de forma juiciosa.
Clonación utilizando un constructor de copia.
Una forma fácil de clonar un objeto es implementando un constructor de copia.
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
Clonación implementando la interfaz clonable
Clonando un objeto implementando la interfaz 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
Clonación realizando una copia superficial.
El comportamiento predeterminado al clonar un objeto es realizar una copia superficial de los campos del objeto. En ese caso, tanto el objeto original como el objeto clonado mantienen referencias a los mismos objetos.
Este ejemplo muestra ese comportamiento.
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));
}
Clonación realizando una copia profunda.
Para copiar objetos anidados, se debe realizar una copia profunda , como se muestra en este ejemplo.
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));
}
Clonación utilizando una fábrica de copias.
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)
}
}