Рубрики
Без рубрики

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

Вот как создавать конструкторы копирования в Java и почему реализация Cloneable-не такая уж отличная идея.

Автор оригинала: baeldung.

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 мы также можем использовать метод clone для создания объекта из существующего объекта. Однако конструктор копирования имеет некоторые преимущества перед методом clone :

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

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

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

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

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());
    }
}

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

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

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

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

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

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

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

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

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

Employee clone = source.copy();

5. Заключение

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

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

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