И открывается экспорт разницы java9

Java задняя часть

последовательность

В этой статье в основном изучается разница между открытием и экспортом 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) использование классов во всех именованных модулях.

doc