本文主要研究下java9 opens与exports的区别html
主要用于解决deep reflection问题,open的做用是表示该模块下的全部的包在runtime都容许deep reflection(
包括public及private类型
) 可是编译时期,仅仅容许该module中声明过exports的包能够访问,若是没有exports则该包的类在编译时期不可读java
用于声明该模块的指定包在runtime容许使用反射访问apache
表示容许在编译时和运行时访问指定包的public成员bash
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 packt.lib {
exports com.packt.lib;
}
复制代码
这里没有exports及opens com.packt.lib.sub1maven
编译报错
)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 packt.lib {
exports com.packt.lib;
opens com.packt.lib.sub1;
}
复制代码
因为没有exports,则编译不过模块化
[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 中声明, 但该模块未导出它)
复制代码
像上面那种直接引用包名来反射的,不会报错,由于编译能够经过,运行正常ui
module packt.lib {
exports com.packt.lib;
exports com.packt.lib.sub1;
}
复制代码
能够编译经过,运行报错spa
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.
复制代码
能够编译经过,运行报错code
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.
复制代码
open module packt.lib {
exports com.packt.lib;
}
复制代码
这种状况,若是是直接访问该类来使用反射,因为没有exports该package,则直接编译报错htm
这种状况编译能够经过,运行正常
open module packt.lib {
exports com.packt.lib;
exports com.packt.lib.sub1;
}
复制代码
两种访问方式的反射均正常编译及运行。
open的做用是表示该模块下的全部的包在runtime都容许deep reflection(
包括public及private类型
);opens package的做用只是容许该包在runtime都容许deep reflection
open及opens都仅仅是开放runtime时期的能够经过反射访问(
蕴含了运行时的exports
)。
编译及运行时
)若是反射不直接经过类名调用,只是运行时经过包名使用,则只需open或opens便可 若是是经过类名来反射,因为用到了该类,须要经过exports指定能够访问,不指定则编译期当即报错 若是是经过类名来反射使用public方法或newInstance,若是没有exports,则运行时报错 若是有exports,可是没有open,所以编译经过运行时报错
--illegal-access默认是permit,表示容许unnamed modules反射(java.lang.reflect/java.lang.invoke)使用全部named modules中的类