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 public
và protected
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 .
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 đó. –
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
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. –