Java Copy Constructor

1. Giới thiệu

Một phương thức khởi tạo sao chép trong một lớp Java là một phương thức khởi tạo tạo một đối tượng bằng cách sử dụng một đối tượng khác của cùng một lớp Java .

Điều đó rất hữu ích khi chúng ta muốn sao chép một đối tượng phức tạp có nhiều trường hoặc khi chúng ta muốn tạo một bản sao sâu của một đối tượng hiện có.

2. Cách tạo mã lệnh sao chép

Để tạo một phương thức khởi tạo sao chép, trước tiên chúng ta có thể khai báo một phương thức khởi tạo nhận một đối tượng cùng kiểu làm tham số:

public class Employee { private int id; private String name; public Employee(Employee employee) { } }

Sau đó, chúng tôi sao chép từng trường của đối tượng đầu vào vào thể hiện mới:

public class Employee { private int id; private String name; public Employee(Employee employee) { this.id = employee.id; this.name = employee.name; } }

Những gì chúng ta có ở đây là một bản sao cạn , điều này tốt vì tất cả các trường của chúng ta - một int và một Chuỗi trong trường hợp này - đều là kiểu nguyên thủy hoặc kiểu bất biến.

Nếu lớp Java có các trường có thể thay đổi, thì thay vào đó chúng ta có thể tạo một bản sao sâu bên trong phương thức khởi tạo bản sao của nó. Với bản sao sâu, đối tượng mới được tạo độc lập với đối tượng gốc vì chúng tôi tạo một bản sao riêng biệt của từng đối tượng có thể thay đổi:

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. Copy Constructor so với Clone

Trong Java, chúng ta cũng có thể sử dụng phương thức nhân bản để tạo một đối tượng từ một đối tượng hiện có. Tuy nhiên, phương thức sao chép có một số ưu điểm so với phương thức sao chép :

  1. Hàm tạo bản sao dễ thực hiện hơn nhiều. Chúng ta không cần triển khai giao diện Cloneable và xử lý CloneNotSupportedException .
  2. Các bản sao phương thức trả về một vị tướng Object tham khảo. Do đó, chúng ta cần đánh máy nó thành kiểu thích hợp.
  3. Chúng tôi không thể gán giá trị cho trường cuối cùng trong phương thức sao chép . Tuy nhiên, chúng ta có thể làm như vậy trong hàm tạo bản sao.

4. Các vấn đề về thừa kế

Các hàm tạo sao chép trong Java không được các lớp con kế thừa. Do đó, nếu chúng ta cố gắng khởi tạo một đối tượng con từ một tham chiếu lớp cha, chúng ta sẽ gặp phải vấn đề ép kiểu khi sao chép nó bằng hàm tạo bản sao.

Để minh họa vấn đề này, trước tiên hãy tạo một lớp con của Employee và phương thức khởi tạo bản sao của nó:

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

Sau đó, chúng ta khai báo một biến Employee và khởi tạo nó bằng hàm tạo Manager :

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

Vì kiểu tham chiếu là Employee , chúng ta phải truyền nó sang kiểu Manager để có thể sử dụng hàm tạo bản sao của lớp Manager :

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

Chúng ta có thể nhận được ClassCastException trong thời gian chạy nếu đối tượng đầu vào không phải là một thể hiện của lớp Manager .

Một cách để tránh ép kiểu trong hàm tạo bản sao là tạo một phương thức có thể kế thừa mới cho cả hai lớp:

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

Trong mỗi phương thức của lớp, chúng ta gọi hàm tạo bản sao của nó với đầu vào là đối tượng này . Bằng cách này, chúng tôi có thể đảm bảo rằng đối tượng được tạo bằng đối tượng người gọi:

Employee clone = source.copy();

5. Kết luận

Trong hướng dẫn này, chúng tôi đã chỉ ra cách tạo một hàm tạo bản sao với một số ví dụ về mã. Ngoài ra, chúng tôi đã thảo luận một số lý do tại sao chúng ta nên tránh phương pháp nhân bản .

Hàm tạo sao chép gặp sự cố ép kiểu khi chúng ta sử dụng nó để sao chép một đối tượng lớp con có kiểu tham chiếu là lớp cha. Chúng tôi đã cung cấp một giải pháp cho vấn đề này.

Như mọi khi, mã nguồn của hướng dẫn có sẵn trên GitHub.