对非导出包中的类的Java 14 Jigsaw反射不会拒绝访问
我在玩拼图。我有一个简单的可复制代码对非导出包中的类的Java 14 Jigsaw反射不会拒绝访问,java,reflection,java-platform-module-system,Java,Reflection,Java Platform Module System,我在玩拼图。我有一个简单的可复制代码 package university.harvard; public class Pilot{ public static void main(final String args[]){ callInNotAExportedPackage(); } private static void callInNotAExportedPackage(){ try{ final Class
package university.harvard;
public class Pilot{
public static void main(final String args[]){
callInNotAExportedPackage();
}
private static void callInNotAExportedPackage(){
try{
final Class<?>classy = Class.forName("javax.swing.JButton");
System.out.println(classy.newInstance());
}catch(final Exception e){
e.printStackTrace();
}
}
}
我可以用这个命令编译模块
C:\Ocp11>javac -d out --module-source-path src -m John
Note: src\John\Pilot.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
我收到了有关弃用的消息,但编译成功。在这一点上,我说编译器不知道我将尝试调用一个类,而不是一个导出的包
当我运行模块时
C:\Ocp11>java -p out -m John/university.harvard.Pilot
我可以看到,通过反射检索实例没有问题
javax.swing.JButton[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.5,border=javax.
swing.plaf.BorderUIResource$CompoundBorderUIResource@3498ed,flags=296,maximumSiz
e=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,
margin=javax.swing.plaf.InsetsUIResource[top=2,left=14,bottom=2,right=14],paintB
order=true,paintFocus=true,pressedIcon=,rolloverEnabled=true,rolloverIcon=,rollo
verSelectedIcon=,selectedIcon=,text=,defaultCapable=true]
但这是什么?我以为拼图会挡住我
如果我像这样在代码中输入完全限定的类名
module John{
exports university.harvard;
}
final Class<?>classy = Class.forName("javax.swing.JButton");
final javax.swing.JButton button = (javax.swing.JButton)classy.newInstance();
System.out.println(button);
但是,我没有使用完全限定的类名,我可以绕过Jigsaw
我知道,如果不提及它,我将无能为力,但我认为Jigsaw允许我这么做有些奇怪
我正在使用
C:\Ocp11>java --version
java 14 2020-03-17
Java(TM) SE Runtime Environment (build 14+36-1461)
Java HotSpot(TM) 64-Bit Server VM (build 14+36-1461, mixed mode, sharing)
问题的标题是 对非导出包中的类的Java 14 Jigsaw反射不会拒绝访问 但实际上,您试图访问的类位于导出的包中。类
javax.swing.JButton
位于模块java.desktop
的包javax.swing
中,该包被导出:
/[License&Javadoc]
模块java.desktop{
//[其他出口和需求]
导出javax.swing;
//[其他导出、打开、使用和提供]
}
由于模块在运行时可用,Class.forName(“javax.swing.JButton”)
不会引发异常(否则它会引发java.lang.ClassNotFoundException
)。它可能是可用的,因为它是根模块(请参阅和)
即使该类不在导出包中,也可以:
Class aClass=Class.forName(“sun.java2d.marlin.Curve”);//将编译并运行
但是,(javax.swing.JButton)classy.newInstance()
不会编译-不是因为包没有导出,而是因为您的模块,John
没有读取它。要使其正常工作,您的模块需要一个requires java.desktop代码>如下所示:
模块John{
需要java.desktop;
哈佛大学;
}
这样模块John
就能够读取java.desktop
导出的所有包
调用classy.newInstance()代码>(不带类型转换)将编译,因为编译器不知道新实例的类型
以下是一些在运行时和编译时起作用的示例以及原因(不):
/(1)将编译并运行:
Class curveClass=Class.forName(“sun.java2d.marlin.Curve”);
//(2)将编译但不运行,即使模块`requires java.desktop;`:
对象curveObject=curveClass.newInstance();
//(3)即使模块有`requires java.desktop;`:
sun.java2d.marlin.Curve Curve=(sun.java2d.marlin.Curve)curveClass.newInstance();
//(4)将编译并运行:
类jButtonClass=Class.forName(“javax.swing.JButton”);
//(5)将编译并运行,即使模块没有“requires java.desktop;”:
对象jButtonObject=jButtonClass.newInstance();
//(6)仅当模块`requires java.desktop;`:
javax.swing.JButton JButton=(javax.swing.JButton)jButtonClass.newInstance();
只保存类的信息/特征,所以这种访问是可以的
将编译,因为编译器不知道新实例的类型为sun.java2d.marlin.Curve
。但是,在运行时,访问将被阻止
甚至不会编译,因为编译器知道类型,因此知道访问是非法的
同(1)
将编译,原因与(2)相同,并将运行,因为包实际已导出
仅当模块有需要java.desktop时才会编译因为编译器知道类型
C:\Ocp11>java --version
java 14 2020-03-17
Java(TM) SE Runtime Environment (build 14+36-1461)
Java HotSpot(TM) 64-Bit Server VM (build 14+36-1461, mixed mode, sharing)