Перейти к основному содержимому

Конструктор копирования Java

· 3 мин. чтения

1. Введение

Конструктор копирования в классе Java — это конструктор , который создает объект, используя другой объект того же класса Java .

Это полезно, когда мы хотим скопировать сложный объект с несколькими полями или когда мы хотим сделать глубокую копию существующего объекта.

2. Как создать конструктор копирования

Чтобы создать конструктор копирования, мы можем сначала объявить конструктор, который принимает объект того же типа в качестве параметра:

public class Employee {
private int id;
private String name;

public Employee(Employee employee) {
}
}

Затем мы копируем каждое поле входного объекта в новый экземпляр:

public class Employee {
private int id;
private String name;

public Employee(Employee employee) {
this.id = employee.id;
this.name = employee.name;
}
}

Здесь у нас поверхностная копия , и это нормально, поскольку все наши поля — в данном случае int и String — являются либо примитивными, либо неизменяемыми типами .

Если в классе Java есть изменяемые поля, мы можем вместо этого сделать глубокую копию внутри его конструктора копирования. При глубокой копии вновь созданный объект не зависит от исходного, потому что мы создаем отдельную копию каждого изменяемого объекта:

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. Копировать конструктор против клона

В Java мы также можем использовать метод клонирования для создания объекта из существующего объекта. Однако конструктор копирования имеет некоторые преимущества перед методом клонирования :

  1. Конструктор копирования реализовать намного проще. Нам не нужно реализовывать интерфейс Cloneable и обрабатывать CloneNotSupportedException .
  2. Метод clone возвращает общую ссылку на объект . Поэтому нам нужно привести его к соответствующему типу.
  3. Мы не можем присвоить значение конечному полю в методе клонирования . Однако мы можем сделать это в конструкторе копирования.

4. Вопросы наследования

Конструкторы копирования в Java не наследуются подклассами. Поэтому, если мы попытаемся инициализировать дочерний объект из ссылки на родительский класс, мы столкнемся с проблемой приведения при клонировании его с помощью конструктора копирования.

Чтобы проиллюстрировать эту проблему, давайте сначала создадим подкласс Employee и его конструктор копирования:

public class Manager extends Employee {
private List<Employee> directReports;
// ... other constructors

public Manager(Manager manager) {
super(manager.id, manager.name, manager.startDate);
this.directReports = directReports.stream()
.collect(Collectors.toList());
}
}

Затем мы объявляем переменную Employee и создаем ее экземпляр с помощью конструктора Manager :

Employee source = new Manager(1, "ForEach Manager", startDate, directReports);

Поскольку ссылочным типом является Employee , мы должны привести его к типу Manager , чтобы мы могли использовать конструктор копирования класса Manager :

Employee clone = new Manager((Manager) source);

Мы можем получить ClassCastException во время выполнения, если входной объект не является экземпляром класса Manager .

Один из способов избежать приведения в конструкторе копирования — создать новый наследуемый метод для обоих классов:

public class Employee {
public Employee copy() {
return new Employee(this);
}
}

public class Manager extends Employee {
@Override
public Employee copy() {
return new Manager(this);
}
}

В каждом методе класса мы вызываем его конструктор копирования с вводом этого объекта. Таким образом, мы можем гарантировать, что сгенерированный объект равен вызывающему объекту:

Employee clone = source.copy();

5. Вывод

В этом руководстве мы показали, как создать конструктор копирования с некоторыми примерами кода. Кроме того, мы обсудили несколько причин, по которым нам следует избегать метода клонирования .

Конструктор копирования имеет проблему приведения, когда мы используем его для клонирования объекта дочернего класса, ссылочный тип которого является родительским классом. Мы предоставили одно решение для этой проблемы.

Как всегда, исходный код руководства доступен на GitHub .