对非导出包中的类的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)