2011-08-16 36 views
60

Cách tốt nhất là không để lộ các tham chiếu bên trong của một đối tượng (thực thể). Vì vậy, nếu một Object có một trường kiểu java.util.Date thì ví dụ getter cho trường này sẽ trả về không phải là ngày ban đầu mà là một bản sao của nó.java.util.Date sao chép hoặc sao chép để không hiển thị tham chiếu nội bộ

Nhưng đối với một java.util.Date có hai cách phổ biến để tạo ra bản sao:

  • bản sao: (Date) originalDate.clone()
  • bản sao qua constructor new Date(originalDate.getTime())

Câu hỏi của tôi là, mà cách tốt hơn, và tại sao?

Trả lời

40

Nếu nó chắc chắn chỉ là Date, nó sẽ không tạo ra bất kỳ sự khác biệt nào.

Nếu đối tượng thực tế có thể là một lớp con của Date (như java.sql.Date) sau đó tôi muốn hy vọng rằng clone() sẽ bảo vệ các thông tin thêm (bao gồm trong đó lớp nó là) trong khi kêu gọi các nhà xây dựng sẽ không được.

Là một sang một bên, nếu bạn sử dụng Joda Time bạn sẽ không gặp phải vấn đề này, vì có rất nhiều loại bất biến để sử dụng. Đó cũng là một API tốt hơn nhiều :)

+6

Vì Java 8 java.time API có thể được sử dụng thay cho Joda Time. – Akash

33

Đọc Effective Java. Cách ưu tiên để tạo các bản sao là sử dụng phương thức khởi tạo bản sao.

Venners hóa đơn: Trong sách của bạn, bạn khuyên bạn nên sử dụng một hàm tạo bản sao thay vì thực hiện Cloneeable và viết bản sao. Bạn có thể giải thích về điều đó không?

Josh Bloch: Nếu bạn đã đọc mục về nhân bản trong cuốn sách của tôi, đặc biệt là nếu bạn đọc giữa các dòng, bạn sẽ biết rằng tôi nghĩ rằng bản sao bị hỏng sâu. Có một vài lỗi thiết kế, lớn nhất của đó là giao diện Cloneable không có phương thức sao chép. Và điều đó có nghĩa là nó không hoạt động: làm một cái gì đó Cloneable không nói bất cứ điều gì về những gì bạn có thể làm với nó. Thay vào đó, nó nói một cái gì đó về những gì nó có thể làm trong nội bộ. Nó nói rằng nếu bằng cách gọi super.clone nhiều lần nó kết thúc lên gọi phương thức sao chép của Object, phương thức này sẽ trả về một bản sao trường của bản gốc.

+5

Đó là cách ưu tiên để thiết kế nhân bản trong các lớp của riêng bạn, mặc dù nó yêu cầu người gọi đến * know * mà lớp con cụ thể được sử dụng hay không * care * mà lớp con cụ thể được sử dụng. Xem câu trả lời của tôi cho một ví dụ về cách nó có thể tạo sự khác biệt. –

14

Nếu bạn đang mã hóa phòng thủ, bạn sẽ muốn người tạo bản sao. Xem this passage from Effective Java:

Cũng lưu ý rằng chúng tôi không sử dụng phương pháp sao chép của Date để tạo bản sao phòng thủ. Bởi vì Date là nonfinal, phương thức clone không đảm bảo trả về một đối tượng có class là java.util.Date; nó có thể trả về một thể hiện của một lớp con không đáng tin cậy được thiết kế đặc biệt cho sự nghịch ngợm độc hại. Ví dụ như một lớp con có thể ghi lại một tham chiếu đến từng cá thể trong một danh sách tĩnh riêng tại thời điểm tạo và cho phép kẻ tấn công truy cập vào danh sách này. Điều này sẽ cung cấp cho các kẻ tấn công miễn phí trị vì tất cả các trường hợp. Để ngăn chặn kiểu tấn công này, không sử dụng phương thức sao chép để tạo bản sao phòng thủ của một tham số có loại được phân lớp bởi các bên không đáng tin cậy.

Các vấn đề liên quan