Tại sao Java không cho phép các thành viên riêng tư trong giao diện? Có lý do cụ thể nào không?
Tại sao Java không cho phép các thành viên riêng tư trong giao diện? Có lý do cụ thể nào không?
Câu trả lời:
Từ Thông số ngôn ngữ Java, (Kiểm soát truy cập) :
"Ngôn ngữ lập trình Java cung cấp các cơ chế để kiểm soát truy cập, để ngăn người dùng của một gói hoặc lớp phụ thuộc vào các chi tiết không cần thiết của việc triển khai gói hoặc lớp đó."
Kiểm soát truy cập là tất cả về ẩn chi tiết triển khai. Một giao diện không có triển khai để ẩn.
Trong Java 9, có thể sử dụng các phương thức private trong các giao diện.
Nhóm biên dịch javac vui mừng thông báo về tính khả dụng của hỗ trợ trình biên dịch cho các phương thức riêng trong các giao diện bắt đầu với bản dựng 9 b54 của JDK.
Các phương thức giao diện riêng là một phần của Java 9 như một phần của JEP-213 . Vì các giao diện trong Java 8 có thể có các phương thức mặc định , các phương thức private cho phép nhiều phương thức mặc định sử dụng một phương thức private được chia sẻ.
Kể từ Java 8, các giao diện có thể có các phương thức mặc định và như Java 9, một giao diện được phép có các phương thức riêng tư mà chỉ có thể được truy cập bằng các phương thức mặc định trong cùng một giao diện.
Một giao diện được sử dụng để mô tả một API được cung cấp bởi bất kỳ lớp nào triển khai giao diện. Vì một giao diện từ định nghĩa của nó không có trạng thái nên không được sử dụng khai báo các thành viên trường trong đó.
Sẽ không có cách nào để triển khai một giao diện như vậy. Một câu trả lời cho câu hỏi mà tôi đã đặt ra cho thấy rằng sẽ không thể (nếu không thay đổi hoàn toàn các quy tắc) để triển khai một giao diện với các phương thức riêng tư - điều này mở ra câu hỏi tại sao các phương thức riêng tư được bảo vệ và gói không được phép.
class OuterClass
{
void run ( MyInterface x )
{
x . publicMethod ( ) ; // why not?
x . protectedMethod ( ) ; // why not?
x . packagePrivateMethod ( ) ; // why not?
x . privateMethod ( ) ; // why not?
}
interface MyInterface
{
public abstract void publicMethod ( ) ; // OK
protected abstract void protectedMethod ( ) ; // why not?
abstract void packagePrivateMethod ( ) ; // in interface default is public, but why not package private
private void privateMethod ( ) ; // impossible to implement
}
class MyImpl implements MyInterface
{
public void publicMethod ( ) { } // ok
protected void protectedMethod ( ) { } // no sweat
void packagePrivateMethod ( ) { } // no sweat
private void privateMethod ( ) { } // not happening
}
}
Đoạn mã dưới đây sẽ đạt được kết quả mong muốn. Mặc dù tất cả các phương pháp đều là công khai, nhưng chỉ phương pháp công khai là công khai hiệu quả. phương pháp bảo vệ được bảo vệ hiệu quả. packagePrivateMethod có hiệu quả là packagePrivate. privateMethod là riêng tư một cách hiệu quả.
class WorkAround
{
void run ( MyPrivateInterface x )
{
x . publicMethod ( ) ;
x . protectedMethod ( ) ;
x . packagePrivateMethod ( ) ;
x . privateMethod ( ) ;
}
public interface MyPublicInterface { void publicMethod ( ) ; }
protected interface MyProtectedInterface extends MyPublicInterface { void protectedMethod ( ) ; }
interface MyPackagePrivateInterface extends MyProtectedInterface { void packagePrivateMethod ( ) ; }
private interface MyPrivateInterface extends MyPackagePrivateInterface { void privateMethod ( ) ; }
}
Theo Javangôn ngữ lập trình, phạm vi của private membersnó được giới hạn trong phạm vi classmà nó được khai báo và chỉ có thể được truy cập bằng các phương thức của nó class. Nhưng intefacekhông có phần thân phương thức do đó không thể sử dụng khai báo các thành viên riêng tư bên trong một interface.
Java cho phép các phương thức riêng trong một giao diện trong Java 9 . Các phương thức mặc định đã được giới thiệu trong Java 8. Có thể nhiều phương thức mặc định muốn chia sẻ một số mã, sau đó mã này có thể được chuyển sang một phương thức riêng tư mà không để lộ nó ra thế giới bên ngoài. Đây lỗi đã được cố định và bắt đầu từ năm JDK 9 build 54, trình biên dịch hỗ trợ cho các phương pháp giao diện tin đã được phục sinh.
public interface IData{
default void processData(int data) {
validate(data);
// do some work with it
}
default void consumeData(int data) {
validate(data);
// do some work with it
}
private void validate(int data) {
// validate data
}
}
Đó là bởi vì chúng sẽ vô dụng.
Sẽ không có cách nào để gọi một phương thức riêng.
Các thành viên tư nhân là một chi tiết thực hiện. Một giao diện là về vai trò chung mà một lớp có thể đảm nhận.
các trường riêng sẽ không hoàn toàn vô dụng vì các trường khác và các lớp bên trong có thể truy cập chúng.
Tuy nhiên, các phương thức private không thể được thực hiện, ngay cả trong các lớp lồng nhau, khiến chúng gần như vô dụng. Bạn có thể đọc chúng bằng cách sử dụng phản chiếu, nhưng đó là một trường hợp phức tạp.
Các thành viên của một lớp được khai báo là private không được kế thừa bởi các lớp con của lớp đó. Chỉ các thành viên của một lớp được khai báo là bảo vệ hoặc công khai mới được kế thừa bởi các lớp con được khai báo trong một gói khác với gói mà lớp được khai báo.
Nguồn
Vì vậy, bạn không có bất kỳ phương thức làm việc nào trong một giao diện có thể hoạt động với trường không kế thừa riêng tư đó, Vậy tại sao nó lại tồn tại?
Đúng, không thể làm điều đó. Đối với tất cả những người bình luận về lý do tại sao nó không nên:
Hãy tưởng tượng tôi có Lớp A, sử dụng giao diện I. Lớp B, mở rộng Lớp A, do đó cũng kế thừa tất cả các phương thức giao diện trong A.
Bây giờ, hãy tưởng tượng tôi muốn có một phương thức riêng trong Lớp A, nhưng cũng muốn nó được định nghĩa theo hợp đồng cho các lớp khác (Có thể là lớp C, không nhất thiết phải mở rộng Lớp B hoặc A).
Có lẽ đối với một phương thức "khởi tạo", mà tôi muốn cho tất cả các lớp sử dụng giao diện I. Nhưng rõ ràng là tôi không muốn một phương thức khởi tạo ở chế độ công khai .... vì nó chỉ nên được sử dụng một lần, hoặc khi lớp cho là cần thiết, không chỉ vì bạn muốn sử dụng tất cả.
Giải pháp duy nhất là một giải pháp thay thế, hoặc đơn giản là buộc phương thức init vào chính các lớp mà không có giao diện.
Tôi hiểu lý do không quá, chắc chắn, nhưng vẫn có thể có ích đôi khi. Rõ ràng là Oracle đồng ý khi họ cho phép các phương thức giao diện riêng tư trong JDK 9.
Những gì tôi đã làm, đối với tôi, là đặt một biến boolean đơn giản, theo cách đó phương thức giao diện (phải là riêng tư) có thể được gắn cờ là true (khởi tạo = true) sau khi được đặt một lần. Sau đó, khi được gọi lại, phương thức chỉ đơn giản là không làm gì cả. Bằng cách này, phương thức giao diện có thể được triển khai dưới dạng công khai, nhưng vì hàm tạo (thuộc lớp của tôi) gọi phương thức trước, điều này đặt biến thành true và vì vậy nó không thể được gọi lại.
Nếu không, bạn sẽ phải thử một cách giải quyết khác nếu bạn chỉ muốn các hoạt động bên trong của lớp sử dụng nó .... có lẽ bản thân một phương thức tự đặt cờ bật và tắt khi nó sử dụng nó. Khi cờ là sai, phương thức không làm gì cả (đây sẽ là khi ai đó gọi nó từ bên ngoài lớp). Tuy nhiên, khi các lớp sở hữu phương thức gọi nó, chúng nhanh chóng đặt cờ thành true, sau đó gọi phương thức, sau đó đặt cờ thành false ??
Cuối cùng là loại câm. Có lẽ tốt hơn bây giờ chỉ cần đặt lớp riêng vào chính lớp đó và cắt bỏ giao diện hoàn toàn.