无法从另一个模块反射实例化 "opened" 包的 "protected" class

Unable to Reflectively Instantiate a "protected" class of an "opened" package, from another module

总结

我无法跨模块边界反射实例化 class。 class 具有包级访问权限,我试图不仅从包外部实例化它,而且从模块本身外部实例化它。根据我的理解,我可以这样做,只要包含包已被包含模块 open 编辑,并且实例化模块 requires 包含模块。我尝试实例化得到的只是 IllegalAccessException

详情

我的应用程序在我的 Netbeans 11 中配置为 "Modular Java project",在 Java 12 平台上配置为 运行。

在应用程序中,我有两个模块:

mod.world 是我的 "main" 模块——它有 main() 方法,它声明它 requires 另一个模块 mod.vehicles

mod.vehicles 在包 vehicles.cars[ 中定义了一个名为 vehicles.cars.Sedan 的 "protected" class(具有包级访问权限的 class) =56=]

mod.vehicles 声明它 opens vehicles.cars

main() 方法中,我尝试实例化 Sedan class,使用:

var myConstructor = Class.forName("vehicles.cars.Sedan").
                                        getDeclaredConstructor();

myConstructor.newInstance();

我期待看到的

我希望代码成功实例化 Sedan class,并执行 Sedan 构造函数中的 println()

我实际得到的

但是 newInstance() 的调用抛出 IllegalAccessException:

Exception in thread "main" java.lang.IllegalAccessException: class world.MyMainClass (in module mod.world) cannot access a member of class vehicles.cars.Sedan (in module mod.vehicles) with modifiers "public"

我的问题

根据Java Language Specification(第 7.7.2 节导出和打开的包):

The opens directive specifies the name of a package to be opened by the current module. For code in other modules, this grants access at run time, but not compile time, to the public and protected types in the package, and the public and protected members of those types. It also grants reflective access to all types in the package, and all their members, for code in other modules.

  1. 以上摘自JLS的理解是我应该 能够访问 "protected" 类型 Sedan 及其成员, 其中包括构造函数。但为什么我不能使用它 构造函数以反射方式实例化 Sedan class?

  2. 我违反了Java Language Specification的哪一部分 尝试这个实例化?

  3. 我对反射访问这个术语的理解有误吗?这个术语是由 Java 在某处正式定义的吗?无法在 Java 12.

  4. 的 JLS 中的任何地方找到 反射访问 的正式定义

完整代码如下:


module-info.java 对于 mod.world 模块:

module mod.world {
    exports world;
    requires mod.vehicles;
}

MyMainClass.java,在模块 mod.world 的包 world 中:

package world;

import java.lang.reflect.InvocationTargetException;

public class MyMainClass {
    public static void main (String[] args) throws ClassNotFoundException,
                                                NoSuchMethodException,
                                                InstantiationException,
                                                IllegalAccessException,
                                                InvocationTargetException {

        // This statement succeeds.
        var myConstructor = Class.forName("vehicles.cars.Sedan").
                                                getDeclaredConstructor();

        // This statement throws IllegalAccessException
        myConstructor.newInstance();
    }
}

module-info.java 对于 mod.vehicles 模块:

module mod.vehicles {
    opens vehicles.cars;
}

Sedan.javavehicles.cars:

package vehicles.cars;

class Sedan {
    public Sedan () {
        System.out.println ("Inside constructor Sedan()");
    }
}

其他观察

如果我将 Sedan class 更改为 public,则实例化成功。

因为Sedan是包私有的,你需要调用myConstructor.setAccessible​(true)

opens 允许您调用 setAccessible​,它并不能消除调用的需要。