Các lý do chính đáng để cấm kế thừa trong Java là gì, ví dụ bằng cách sử dụng các lớp hoặc các lớp cuối cùng bằng cách sử dụng một hàm tạo không tham số riêng tư? Những lý do tốt để làm cho một phương pháp cuối cùng là gì?
Các lý do chính đáng để cấm kế thừa trong Java là gì, ví dụ bằng cách sử dụng các lớp hoặc các lớp cuối cùng bằng cách sử dụng một hàm tạo không tham số riêng tư? Những lý do tốt để làm cho một phương pháp cuối cùng là gì?
Câu trả lời:
Tài liệu tham khảo tốt nhất của bạn ở đây là Mục 19 của cuốn sách tuyệt vời "Java hiệu quả" của Joshua Bloch, được gọi là "Thiết kế và tài liệu để thừa kế hoặc nếu không thì cấm". (Đó là mục 17 trong phiên bản thứ hai và mục 15 trong phiên bản đầu tiên.) Bạn thực sự nên đọc nó, nhưng tôi sẽ tóm tắt.
Sự tương tác của các lớp được thừa kế với cha mẹ của chúng có thể gây ngạc nhiên và không thể lường trước được nếu tổ tiên không được thiết kế để được thừa kế từ đó.
Các lớp học do đó nên có hai loại:
Các lớp được thiết kế để được mở rộng và có đủ tài liệu để mô tả cách thực hiện
Các lớp được đánh dấu cuối cùng
Nếu bạn đang viết mã nội bộ hoàn toàn thì đây có thể là một chút quá mức cần thiết. Tuy nhiên, nỗ lực thêm liên quan đến việc thêm năm ký tự vào một tệp lớp là rất nhỏ. Nếu bạn chỉ viết cho tiêu chuẩn nội bộ thì một lập trình viên tương lai luôn có thể xóa 'bản cuối cùng' - bạn có thể nghĩ về nó như một lời cảnh báo rằng "lớp này không được thiết kế với tính kế thừa".
Bạn có thể muốn làm cho một phương thức cuối cùng để các lớp ghi đè không thể thay đổi hành vi được tính trong các phương thức khác. Các phương thức được gọi trong constructor thường được khai báo là cuối cùng để bạn không gặp phải bất ngờ khó chịu nào khi tạo đối tượng.
final
.
Một lý do để thực hiện một trận chung kết lớp sẽ là nếu bạn muốn buộc thành phần trên kế thừa. Điều này thường được mong muốn trong việc tránh khớp nối chặt chẽ giữa các lớp.
Có 3 trường hợp sử dụng mà bạn có thể đi cho các phương pháp cuối cùng.
Mục đích để thực hiện một trận chung kết lớp:
Vì vậy, không có cơ thể có thể mở rộng các lớp và thay đổi hành vi của họ.
Ví dụ: Integpper lớp Integer là lớp cuối cùng. Nếu lớp đó không phải là cuối cùng, thì bất kỳ ai cũng có thể mở rộng Integer thành lớp của riêng mình và thay đổi hành vi cơ bản của lớp nguyên. Để tránh điều này, java đã tạo tất cả các lớp bao bọc như các lớp cuối cùng.
DerivedInteger
, nó vẫn không thay đổi lớp Integer ban đầu và bất cứ ai sử dụng DerivedInteger
đều có nguy cơ của riêng họ, vì vậy tôi vẫn không hiểu tại sao đó là vấn đề.
bạn có thể muốn tạo các đối tượng bất biến ( http://en.wikipedia.org/wiki/Immutable_object ), bạn có thể muốn tạo một singleton ( http://en.wikipedia.org/wiki/Singleton_potype ) hoặc bạn có thể muốn để ngăn người khác ghi đè phương thức vì lý do hiệu quả, an toàn hoặc bảo mật.
Kế thừa giống như một cái cưa - rất mạnh mẽ, nhưng khủng khiếp trong tay kẻ xấu. Hoặc bạn thiết kế một lớp được kế thừa (có thể hạn chế tính linh hoạt và mất nhiều thời gian hơn) hoặc bạn nên cấm nó.
Xem các mục Phiên bản Java 2 hiệu quả 16 và 17 hoặc bài đăng trên blog của tôi "Thuế thừa kế" .
Hmmm ... tôi có thể nghĩ về hai điều:
Bạn có thể có một lớp liên quan đến các vấn đề bảo mật nhất định. Bằng cách phân lớp nó và cung cấp cho hệ thống của bạn phiên bản phân lớp của nó, kẻ tấn công có thể phá vỡ các hạn chế bảo mật. Ví dụ: ứng dụng của bạn có thể hỗ trợ các plugin và nếu một plugin chỉ có thể phân lớp các lớp liên quan đến bảo mật của bạn, thì ứng dụng đó có thể sử dụng thủ thuật này để bằng cách nào đó đưa một phiên bản được phân lớp của nó vào vị trí. Tuy nhiên, đây là điều mà Sun phải giải quyết liên quan đến các applet và những thứ tương tự, có thể không phải là một trường hợp thực tế như vậy.
Một thực tế hơn nhiều là để tránh một đối tượng trở nên đột biến. Ví dụ: vì Chuỗi là bất biến, mã của bạn có thể giữ các tham chiếu đến nó một cách an toàn
String blah = someOtherString;
thay vì sao chép chuỗi trước. Tuy nhiên, nếu bạn có thể phân lớp Chuỗi, bạn có thể thêm các phương thức vào chuỗi cho phép sửa đổi giá trị chuỗi, bây giờ không có mã nào có thể tin được nữa rằng chuỗi sẽ giữ nguyên nếu nó chỉ sao chép chuỗi như trên, thay vào đó, nó phải sao chép chuỗi chuỗi.
Nếu bạn đánh dấu các lớp và phương thức là cuối cùng, bạn có thể nhận thấy mức tăng hiệu suất nhỏ, vì thời gian chạy không phải tìm phương thức lớp đúng để gọi cho một đối tượng nhất định. Các phương thức không phải là cuối cùng được đánh dấu là ảo để chúng có thể được mở rộng đúng cách nếu cần, các phương thức cuối cùng có thể được liên kết trực tiếp hoặc biên dịch nội tuyến trong lớp.
Để ngăn chặn mọi người làm những việc có thể gây nhầm lẫn cho bản thân và những người khác. Hãy tưởng tượng một thư viện vật lý nơi bạn có một số hằng số hoặc phép tính xác định. Nếu không sử dụng từ khóa cuối cùng, ai đó có thể xuất hiện và xác định lại các phép tính hoặc hằng số cơ bản KHÔNG BAO GIỜ thay đổi.
Bạn muốn làm cho một phương thức cuối cùng để các lớp ghi đè không thay đổi hành vi của nó. Khi bạn muốn có thể thay đổi hành vi, hãy đặt phương thức ở chế độ công khai. Khi bạn ghi đè một phương thức công khai, nó có thể được thay đổi.