2017-05-17 27 views
9

Tôi đang đọc bản thảo của đặc tả Java 9 nhưng cụm từ này là không rõ ràng với tôi:Các mở chỉ trong Java 9

Các mở chỉ định tên của một gói được mở ra bởi dòng điện mô-đun. Điều này làm cho các loại công cộng và được bảo vệ trong gói, và các thành viên công cộng và được bảo vệ của họ, có thể truy cập để mã trong các mô-đun khác chỉ trong thời gian chạy. Nó cũng làm cho tất cả các loại trong gói, và tất cả các thành viên của chúng, có thể truy cập được thông qua các thư viện phản chiếu của Nền tảng Java SE.

Nếu mở ra làm cho truy cập công cộng và được bảo vệ trong thời gian chạy, điều gì có nghĩa là tất cả các loại trong khu vực gói có thể truy cập thông qua phản ánh?

Tôi không hiểu sự khác biệt giữa thời gian chạy và phản chiếu.

Có vẻ như gói đã mở chỉ có thể truy cập công khai và được bảo vệ trong thời gian chạy (thông qua phản chiếu?) Và các gói khác không được chỉ định với kiểu và thành viên có thể truy cập phản ánh (cũng riêng tư ...).

+1

Tôi không biết nếu tôi hiểu câu hỏi của bạn một cách chính xác nhưng, hãy xem xét rằng ai đó có thể có mã phụ thuộc vào API công khai trong gói. Sau đó, Java 9 đi ra và gói được đóng gói bên trong một mô-đun. Bạn sẽ cần mở mô-đun để tiếp tục sử dụng mã kế thừa đó. –

+0

Tôi cố gắng giải thích một lần nữa: nếu mở cho phép tất cả các loại và tất cả các thành viên của một gói được phản chiếu truy cập tại sao có một trường hợp công cộng và bảo vệ được giải thích? – xdevel2000

+1

Ok cảm ơn. Cũng giống như tôi đã nói, có thể ai đó đang sử dụng các API đó (cách thông thường, không thông qua sự phản chiếu) trước khi gói được đóng gói. Nó có vẻ là một tính năng tương thích ngược. –

Trả lời

6

Hãy nói rằng bạn viết một số mã có sử dụng một lớp công chúng từ thư viện.

import somelibrary.somepackage.SomeClass; // <-- public class from a library. 

public class Main { 

    public static void main(String[] args) { 
     SomeClass.doSomething(); 
    } 

} 

Sau đó, bạn biên dịch mã này và biên dịch tốt, vì lớp bạn đang sử dụng là public.

Bây giờ, trong phiên bản tiếp theo của thư viện, gói được thêm vào một mô-đun, nhưng không được xuất. Điều đó có nghĩa rằng nếu bạn cố gắng chạy mã của bạn với mô-đun mới này trên đường dẫn mô-đun thời gian chạy, nó sẽ ném một ngoại lệ vì bạn đang cố gắng truy cập một gói đóng gói.

Để làm cho mã của bạn hoạt động trở lại, bạn có thể sử dụng tùy chọn dòng lệnh để mở mô-đun này vào mã của bạn, để nó có thể tiếp tục sử dụng gói được đóng gói.

Hoặc, người tạo thư viện có thể thêm opens somepackage; vào định nghĩa mô-đun của thư viện. Điều đó sẽ cho phép bạn chạy mã của bạn bằng phiên bản mới này, nhưng không phải biên dịch bằng mã đó. I E. các thành viên publicprotected chỉ có thể truy cập trong thời gian chạy, nhưng không có sự phản ánh nào liên quan.


Cũng vậy với khi bạn mở rộng một lớp, và muốn truy cập vào một thành viên protected của một lớp siêu đó là trong gói đóng gói.

Nhưng mở ra chỉ thị không làm thay đổi thực tế rằng, nếu trong phiên bản tiếp theo của một thư viện, một phương pháp hoặc trường được làm private, rằng bạn nhận được một IllegalAccessError nếu bạn cố gắng sử dụng nó:

class SomeClass { // <-- the class in the library 
    public static void doSomething() { 
     System.out.println("doSomething"); // contrived example code 
    } 
} 

...

public class Main {  
    public static void main(String... args) throws Exception {  
     SomeClass.doSomething(); // this call compiles fine, 
    }  
} 

sau đó, trong phiên bản tiếp theo của thư viện doSomething được làm private:

private static void doSomething() {...} 

Và được biên dịch lại. Nhưng nếu bạn cố gắng chạy phiên bản cũ của Main với phiên bản mới SomeClass bạn nhận được IllegalAccessError.

Tóm lại, mở chỉ hoạt động cho các thành viên vẫn còn public hoặc protected trong phiên bản mới của thư viện.


Tuy nhiên, trong trường hợp phản ánh, bạn luôn có thể truy cập vào một thành viên private, bằng cách sử dụng setAccessible(true):

public static void main(String... args) throws Exception {  
    Method m = SomeClass.class.getDeclaredMethod("doSomething"); 
    m.setAccessible(true); 
    m.invoke(null); // works Fine 
} 

Vì vậy, trong trường hợp phản ánh, mở ra cũng sẽ làm cho đóng gói các thành viên tin truy cập một lần nữa .

+0

Vâng, đây là câu trả lời hay nên tôi đã bỏ phiếu nhưng trong trường hợp này tôi cũng có thể truy cập vào các thành viên riêng ... vì vậy tôi không hiểu những khác biệt được thể hiện trong đặc điểm kỹ thuật. Trân trọng được xóa những gì được nói trong tài liệu được đăng bởi @ xenteros nhưng trong cùng một thời gian tôi không nghĩ rằng các đặc điểm kỹ thuật là trong lỗi .... cũng nếu nó là trong dự thảo! – xdevel2000

+1

@ xdevel2000 Không, bạn không thể truy cập thành viên 'private' trong trường hợp này (nơi bạn biên dịch dựa vào API' public', được tạo thành 'private' trong phiên bản mới hơn). Bạn sẽ nhận được một 'IllegalAccessError', và việc sử dụng mở sẽ không thay đổi điều đó. –

+0

Xin vui lòng, bạn có thể cung cấp cho tôi một ví dụ hoàn chỉnh về IllegalAccessError không? Bây giờ tôi không thể thử điều này một mình ... Nếu bạn có thể, tất nhiên :) – xdevel2000

3

Gói được mở bởi mô-đun, có thể đủ điều kiện hoặc không đủ tiêu chuẩn.

Các mở chỉ trong một tuyên bố mô-đun tuyên bố một gói được mở để cho phép tất cả các loại trong gói, và tất cả các thành viên của họ, chứ không phải loại chỉ công cộng và các thành viên cộng đồng của họ được phản ánh trên của API có hỗ trợ tin truy cập hoặc một cách để bỏ qua hoặc ngăn chặn kiểm tra truy cập ngôn ngữ Java mặc định .

--Documentation

+0

Tốt ... vì vậy nó có vẻ mâu thuẫn với đặc điểm kỹ thuật ... có lẽ vì nó là dự thảo? – xdevel2000

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