1. Introducción
Un constructor de copia en una clase Java es un constructor que crea un objeto utilizando otro objeto de la misma clase Java .
Eso es útil cuando queremos copiar un objeto complejo que tiene varios campos, o cuando queremos hacer una copia profunda de un objeto existente.
2. Cómo crear un constructor de copias
Para crear un constructor de copia, primero podemos declarar un constructor que toma un objeto del mismo tipo como parámetro:
public class Employee { private int id; private String name; public Employee(Employee employee) { } }
Luego, copiamos cada campo del objeto de entrada en la nueva instancia:
public class Employee { private int id; private String name; public Employee(Employee employee) { this.id = employee.id; this.name = employee.name; } }
Lo que tenemos aquí es una copia superficial , lo cual está bien ya que todos nuestros campos, un int y un String en este caso, son tipos primitivos o tipos inmutables.
Si la clase Java tiene campos mutables, entonces podemos hacer una copia profunda dentro de su constructor de copia. Con una copia profunda, el objeto recién creado es independiente del original porque creamos una copia distinta de cada objeto mutable:
public class Employee { private int id; private String name; private Date startDate; public Employee(Employee employee) { this.id = employee.id; this.name = employee.name; this.startDate = new Date(employee.startDate.getTime()); } }
3. Copiar constructor frente a clonar
En Java, también podemos usar el método de clonación para crear un objeto a partir de un objeto existente. Sin embargo, el constructor de copias tiene algunas ventajas sobre el método de clonación :
- El constructor de copias es mucho más fácil de implementar. No necesitamos implementar la interfaz Cloneable y manejar CloneNotSupportedException .
- El método de clonación devuelve una referencia de objeto general . Por lo tanto, necesitamos encasillarlo al tipo apropiado.
- No podemos asignar un valor a un campo final en el método de clonación . Sin embargo, podemos hacerlo en el constructor de copias.
4. Problemas de herencia
Los constructores de copia en Java no son heredables por subclases. Por lo tanto, si intentamos inicializar un objeto secundario a partir de una referencia de clase principal, enfrentaremos un problema de conversión al clonarlo con el constructor de copia.
Para ilustrar este problema, primero creemos una subclase de Empleado y su constructor de copia:
public class Manager extends Employee { private List directReports; // ... other constructors public Manager(Manager manager) { super(manager.id, manager.name, manager.startDate); this.directReports = directReports.stream() .collect(Collectors.toList()); } }
Luego, declaramos una variable Employee y la instanciamos con el constructor Manager :
Employee source = new Manager(1, "Baeldung Manager", startDate, directReports);
Dado que el tipo de referencia es Empleado , tenemos que convertirlo en el tipo Administrador para poder usar el constructor de copia de la clase Administrador :
Employee clone = new Manager((Manager) source);
Podemos obtener ClassCastException en tiempo de ejecución si el objeto de entrada no es una instancia de la clase Manager .
Una forma de evitar la conversión en el constructor de copia es crear un nuevo método heredable para ambas clases:
public class Employee { public Employee copy() { return new Employee(this); } } public class Manager extends Employee { @Override public Employee copy() { return new Manager(this); } }
En cada método de clase, llamamos a su constructor de copia con la entrada de este objeto. De esta forma, podemos garantizar que el objeto generado sea igual al objeto de la llamada:
Employee clone = source.copy();
5. Conclusión
En este tutorial, mostramos cómo crear un constructor de copia con algunos ejemplos de código. Además, discutimos varias razones por las que deberíamos evitar el método de clonación .
El constructor de copias tiene un problema de conversión cuando lo usamos para clonar un objeto de clase secundaria cuyo tipo de referencia es la clase principal. Proporcionamos una solución para este problema.
Como siempre, el código fuente del tutorial está disponible en GitHub.