Tại sao Java không cho phép các thành viên riêng tư trong giao diện?


82

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?


@pst Tôi đã viết một cách giải quyết ở cuối câu trả lời của mình - stackoverflow.com/a/10169894/348975 . Nó có giải quyết mối quan tâm của bạn không?
emory

Java 9 trở đi được phép của nó. Kiểm tra câu trả lời của tôi bên dưới: stackoverflow.com/questions/10169654/…
akhil_mittal

Câu trả lời:


85

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.


9
Vì chúng ta có thể đặt các lớp lồng nhau bên trong một giao diện, nên chúng ta có thể đặt hiện thực trên giao diện. Làm như vậy là rất sai lầm, nhưng chúng ta có thể.
emory

28
Java 9 cho phép các phương thức riêng trong giao diện, Điều hợp lý là sau khi bổ sung các phương thức mặc định, Tham khảo: bug.openjdk.java.net/browse/JDK-8071453
Hariharan

3
"Làm như vậy là rất sai lầm" .. như mọi khi, tùy thuộc vào ngữ cảnh.
JacksOnF1re

5
Nó không tệ như nó có vẻ. Các phương thức riêng tư trong một giao diện chỉ có thể được truy cập bằng các phương thức mặc định trong cùng giao diện đó. Một trong những lợi ích là giúp phá vỡ việc triển khai các phương thức mặc định thành các hàm nhỏ hơn có ý nghĩa mà không phá vỡ tính đóng gói.
Henry Pham

48

Trong Java 9, có thể sử dụng các phương thức private trong các giao diện.

Thông số kỹ thuật Java 9

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.


10
@SebiSebi, Khoảnh khắc khi bạn nhận ra Java là một ngôn ngữ sống.
Arashsoft 29/09/17

@Arashsoft, OP đang yêu cầu các trường.
Pacerier

19

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ẻ.


13

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.


Điều cần biết về các tính năng giao diện Java-9.
Ravindra babu

9

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 đó.


Trong java land, một thành viên là một trường, phương thức, hàm tạo hoặc lớp.
emory

7

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

6

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.


4

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
   }
}

3

Đó 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.


Tôi không đồng ý với "Sẽ không có cách nào để gọi một phương thức riêng." Với các lớp bên trong, sẽ có một cách - stackoverflow.com/a/10169894/348975
emory

Xem xét các phương thức mặc định của java 8. Giao diện Tôi có các phương thức mặc định A và B với rất nhiều mã phổ biến. Để cấu trúc lại, bạn sẽ muốn phương thức C chỉ chứa mã được chia sẻ và được gọi bởi A và B. Trong Java 8, đây sẽ là một phương thức mặc định được hiển thị cho tất cả các trình triển khai giao diện. trong Java 9 C có thể là một phương pháp tư nhân chỉ hiển thị mặc định phương pháp trong vòng I.
Ivan Krylov

2

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.


Xin lỗi vì đã đào mộ ở đây :( Docs.oracle.com/javase/7/docs/api/java/io/Serializable.html hoạt động như thế nào trong trường hợp này? Mọi người không thể triển khai nó và sau đó ghi đè các phương thức readObject và writeObject ? tôi chắc rằng tôi đang thiếu một cái gì đó
PatrickWalker

1

Các thành viên riêng tư không có ý nghĩa trong giao diện. Giao diện là một cách để truy cập một lớp với các phương thức được xác định mà bạn không cần phải xem nội dung của lớp đó.

Các thành viên tư nhân không đồng ý với điều đó.


0

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?


0

Đú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.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.