последовательность
В этой статье в основном изучается разница между открытием и экспортом java9.
открыть и экспортировать
open
- open module
Он в основном используется для решения проблемы глубокого отражения.Функция открытия заключается в том, чтобы указать, что все пакеты в этом модуле допускают глубокое отражение во время выполнения (
包括public及private类型
) Однако во время компиляции разрешен доступ только к пакетам, для которых в модуле объявлены экспорты.Если экспортов нет, классы пакета недоступны для чтения во время компиляции.
- opens package
Указанный пакет, используемый для объявления этого модуля, разрешает отражающий доступ во время выполнения.
exports
Представляет открытые члены, которые позволяют время для доступа к указанному пакету во время компиляции и во время выполнения
Влияние open и export на отражение
метод отражения
- целевой класс
package com.packt.lib.sub1;
public class Sub1Service {
public Sub1Service() {
System.out.println("Sub1Service being instanced");
}
public void publicMethod() {
System.out.println("public method called!");
}
protected void protectedMethod(){
System.out.println("protected method called...");
}
private void privateMethod(){
System.out.println("private method called...");
}
}
- Отражение имени класса доступа
Sub1Service sub1Service = new Sub1Service();
Method privateMethod = sub1Service.getClass().getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true);
privateMethod.invoke(sub1Service);
- Отразить по имени пакета
Optional<Module> optional = ModuleLayer.boot().findModule("packt.lib");
Class clz = Class.forName(optional.get(),"com.packt.lib.sub1.Sub1Service");
Object sub1 = clz.newInstance();
System.out.println(sub1.getClass().getMethods());
Method publicMethod = sub1.getClass().getDeclaredMethod("publicMethod");
publicMethod.invoke(sub1);
Method protectedMethod = sub1.getClass().getDeclaredMethod("protectedMethod");
protectedMethod.setAccessible(true);
protectedMethod.invoke(sub1);
Method privateMethod = sub1.getClass().getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true);
privateMethod.invoke(sub1);
Нет экспорта, нет открытий
- module-info.java
module packt.lib {
exports com.packt.lib;
}
Экспорта нет и здесь открывается com.packt.lib.sub1
- Отражение по имени класса (
编译报错
)
Exception in thread "main" java.lang.IllegalAccessException: class com.packt.App (in module packt.main) cannot access class com.packt.lib.sub1.Sub1Service (in module packt.lib) because module packt.lib does not export com.packt.lib.sub1 to module packt.main
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
at java.base/jdk.internal.reflect.Reflection.ensureMemberAccess(Reflection.java:107)
at java.base/java.lang.Class.newInstance(Class.java:553)
at packt.main/com.packt.App.main(App.java:25)
- Отразить по имени пакета (
newInstance运行时报错
)
Exception in thread "main" java.lang.IllegalAccessException: class com.packt.App (in module packt.main) cannot access class com.packt.lib.sub1.Sub1Service (in module packt.lib) because module packt.lib does not export com.packt.lib.sub1 to module packt.main
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
at java.base/jdk.internal.reflect.Reflection.ensureMemberAccess(Reflection.java:107)
at java.base/java.lang.Class.newInstance(Class.java:553)
at packt.main/com.packt.App.main(App.java:26)
Экспорта нет, есть открытия
- module-info.java
module packt.lib {
exports com.packt.lib;
opens com.packt.lib.sub1;
}
- Отражение по имени класса
Поскольку экспорта нет, он не будет компилироваться
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.6.2:compile (default-compile) on project main: Compilation failure
[ERROR] /Users/demo/java9-multi-module-demo/main/src/main/java/com/packt/App.java:[30,41] 程序包 com.packt.lib.sub1 不可见
[ERROR] (程序包 com.packt.lib.sub1 已在模块 packt.lib 中声明, 但该模块未导出它)
- Отразить по имени пакета
Прямая ссылка на имя пакета для отражения, как указано выше, не приведет к ошибке, поскольку компиляция может пройти и работать нормально.
При экспорте не открывается
module packt.lib {
exports com.packt.lib;
exports com.packt.lib.sub1;
}
- Отражение по имени класса
Его можно скомпилировать и передать, а при запуске сообщает об ошибке
Sub1Service being instanced
Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make private void com.packt.lib.sub1.Sub1Service.privateMethod() accessible: module packt.lib does not "opens com.packt.lib.sub1" to module packt.main
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:337)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:281)
at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:198)
at java.base/java.lang.reflect.Method.setAccessible(Method.java:192)
at packt.main/com.packt.App.main(App.java:44)
[ERROR] Command execution failed.
- Отразить по имени пакета
Его можно скомпилировать и передать, а при запуске сообщает об ошибке
Sub1Service being instanced
[Ljava.lang.reflect.Method;@4157f54e
public method called!
Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make protected void com.packt.lib.sub1.Sub1Service.protectedMethod() accessible: module packt.lib does not "opens com.packt.lib.sub1" to module packt.main
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:337)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:281)
at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:198)
at java.base/java.lang.reflect.Method.setAccessible(Method.java:192)
at packt.main/com.packt.App.main(App.java:34)
[ERROR] Command execution failed.
Откройте весь модуль напрямую, но без экспорта
- module-info.java
open module packt.lib {
exports com.packt.lib;
}
- Отражение классов прямого доступа
В этом случае, если вы напрямую обращаетесь к классу для использования отражения, поскольку нет экспорта пакета, он будет компилироваться напрямую и сообщать об ошибке.
- Отразить по имени пакета
В этом случае компиляция может пройти, и работа идет нормально
Напрямую открыть весь модуль, есть и экспорт
open module packt.lib {
exports com.packt.lib;
exports com.packt.lib.sub1;
}
Отражение для обоих методов доступа компилируется и работает нормально.
резюме
- Open указывает, что его можно использовать при отражении.
Функция open состоит в том, чтобы указать, что все пакеты в этом модуле допускают глубокое отражение (
包括public及private类型
); роль пакета opens состоит только в том, чтобы разрешить пакету глубокое отражение во время выполнения.
И open, и opens — это только открытые среды выполнения, к которым можно получить доступ через отражение (
蕴含了运行时的exports
).
- exports означает разрешение доступа к общедоступным членам указанного пакета (
编译及运行时
)
Если отражение не вызывается напрямую через имя класса, просто запустите имя пакета, просто откройте или Opens Если это отражено именем класса, из-за этого класса к вам нужно обращаться через Exports, не указанный, сразу сообщается период компиляции. Если это отражено в имени класса, используйте общедоступный метод или newinstance.Если нет экспорта, отчет о времени выполнения неверен. Если экспорт есть, а Open нет, значит компиляция через рантайм
- illegal-access
--illegal-access по умолчанию разрешает, что означает, что безымянным модулям разрешено отражать (java.lang.reflect/java.lang.invoke) использование классов во всех именованных модулях.