Конструктор за копиране на Java

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. Методът на клониране връща обща препратка към обект . Следователно трябва да го въведем на подходящ тип.
  3. Не можем да присвоим стойност на крайно поле в метода на клониране . Въпреки това можем да го направим в конструктора за копиране.

4. Проблеми с наследството

Конструкторите за копиране в Java не се наследяват от подкласове. Следователно, ако се опитаме да инициализираме детски обект от референция на родителски клас, ще се сблъскаме с проблем с кастинга, когато го клонираме с конструктора за копиране.

За да илюстрираме този проблем, нека първо създадем подклас на служител и неговия конструктор за копиране:

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 .

Един от начините да се избегне отливането в конструктора за копиране е да се създаде нов наследствен метод и за двата класа:

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.