Java 8 cho phép các phương thức giao diện tĩnh
Với Java 8, các giao diện có thể có các phương thức tĩnh. Họ cũng có thể có các phương thức cá thể cụ thể, nhưng không phải là các trường mẫu.
Thực sự có hai câu hỏi ở đây:
- Tại sao, trong những ngày xưa tồi tệ, các giao diện không thể chứa các phương thức tĩnh?
- Tại sao các phương thức tĩnh không thể bị ghi đè?
Phương thức tĩnh trong giao diện
Không có lý do kỹ thuật mạnh mẽ tại sao các giao diện không thể có các phương thức tĩnh trong các phiên bản trước. Điều này được tóm tắt độc đáo bởi poster của một câu hỏi trùng lặp. Các phương thức giao diện tĩnh ban đầu được coi là một thay đổi ngôn ngữ nhỏ, và sau đó đã có một đề xuất chính thức để thêm chúng vào Java 7, nhưng sau đó đã bị loại bỏ do các biến chứng không lường trước được.
Cuối cùng, Java 8 đã giới thiệu các phương thức giao diện tĩnh, cũng như các phương thức cá thể có khả năng ghi đè với cách triển khai mặc định. Họ vẫn không thể có các trường ví dụ. Các tính năng này là một phần của hỗ trợ biểu thức lambda và bạn có thể đọc thêm về chúng trong Phần H của JSR 335.
Ghi đè các phương thức tĩnh
Câu trả lời cho câu hỏi thứ hai phức tạp hơn một chút.
Các phương thức tĩnh có thể phân giải được tại thời gian biên dịch. Công văn động có ý nghĩa đối với các phương thức ví dụ, trong đó trình biên dịch không thể xác định loại cụ thể của đối tượng và do đó, không thể giải quyết phương thức để gọi. Nhưng việc gọi một phương thức tĩnh đòi hỏi phải có một lớp và vì lớp đó được biết là tĩnh, thời gian biên dịch thời gian biên dịch động không cần thiết.
Một chút nền tảng về cách các phương thức hoạt động là cần thiết để hiểu những gì đang diễn ra ở đây. Tôi chắc rằng việc triển khai thực tế khá khác nhau, nhưng hãy để tôi giải thích khái niệm của tôi về việc gửi phương thức, mô hình nào quan sát chính xác hành vi.
Giả sử rằng mỗi lớp có một bảng băm ánh xạ chữ ký phương thức (tên và loại tham số) thành một đoạn mã thực tế để thực hiện phương thức. Khi máy ảo cố gắng gọi một phương thức trên một cá thể, nó truy vấn đối tượng cho lớp của nó và tìm kiếm chữ ký được yêu cầu trong bảng của lớp. Nếu một cơ thể phương thức được tìm thấy, nó được gọi. Mặt khác, lớp cha của lớp được lấy và việc tra cứu được lặp lại ở đó. Điều này tiến hành cho đến khi phương thức được tìm thấy, hoặc không có thêm các lớp cha mẹ mà kết quả là a NoSuchMethodError
.
Nếu cả siêu lớp và một lớp con đều có một mục trong các bảng của chúng cho cùng một chữ ký phương thức, thì phiên bản của lớp con sẽ được bắt gặp trước và phiên bản của lớp siêu lớp không bao giờ được sử dụng, đây là "ghi đè".
Bây giờ, giả sử chúng ta bỏ qua thể hiện đối tượng và chỉ bắt đầu với một lớp con. Việc giải quyết có thể tiến hành như trên, cung cấp cho bạn một loại phương thức tĩnh "có thể ghi đè". Tuy nhiên, độ phân giải có thể xảy ra tại thời gian biên dịch, do trình biên dịch bắt đầu từ một lớp đã biết, thay vì đợi cho đến khi bộ thực thi truy vấn một đối tượng thuộc loại không xác định cho lớp của nó. Không có điểm nào trong việc "ghi đè" một phương thức tĩnh vì người ta luôn có thể chỉ định lớp có chứa phiên bản mong muốn.
Trình xây dựng "giao diện"
Đây là một ít tài liệu hơn để giải quyết các chỉnh sửa gần đây cho câu hỏi.
Có vẻ như bạn muốn bắt buộc một cách hiệu quả một phương thức giống như hàm tạo cho mỗi lần thực hiện IXMLizable
. Hãy quên việc cố gắng thực thi điều này với một giao diện trong một phút và giả vờ rằng bạn có một số lớp đáp ứng yêu cầu này. Làm thế nào bạn sẽ sử dụng nó?
class Foo implements IXMLizable<Foo> {
public static Foo newInstanceFromXML(Element e) { ... }
}
Foo obj = Foo.newInstanceFromXML(e);
Vì bạn phải đặt tên rõ ràng cho loại cụ thể Foo
khi "xây dựng" đối tượng mới, trình biên dịch có thể xác minh rằng nó thực sự có phương thức xuất xưởng cần thiết. Và nếu không, vậy thì sao? Nếu tôi có thể thực hiện một IXMLizable
cái thiếu "hàm tạo" và tôi tạo một cá thể và chuyển nó vào mã của bạn, thì đó là một IXMLizable
giao diện cần thiết.
Xây dựng là một phần của việc thực hiện, không phải giao diện. Bất kỳ mã nào hoạt động thành công với giao diện đều không quan tâm đến hàm tạo. Bất kỳ mã nào quan tâm đến hàm tạo cần phải biết loại cụ thể và giao diện có thể bị bỏ qua.