有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java9中的java如果我不知道类的模块,如何反射地加载它?

假设我有一个应用程序,给定了一个众所周知的包名和类,我需要反射地加载该类,并从中调用一些方法。假设这个类在另一个java jar(“库”)中可用

到目前为止,在Java9之前,由于类路径中的所有类都是可用的,所以实现这一点很简单

但是,在Java 9中,如果应用程序“模块”不需要“库”包,则无法访问库类

如何使用模块化的JAR实现相同的行为

例如:

这是我的申请表:

// This is defined in ReflectionApp.jar
// ReflectionApp
// └── src
//     ├── module-info.java
//     └── org
//         └── reflection
//             └── app
//                 └── ReflectionApp.java
//
package org.reflection.app;

import java.lang.reflect.Method;

public class ReflectionApp {
    private static final String PACKAGE = "org.reflection.lib";
    private static final String CLASS = "ReflectiveClass";
    private static final String METHOD = "doSomeWork";

    public static void main(String[] args) throws Exception {

        // This will not work using java9
        Class<?> klass = Class.forName(String.format("%s.%s", PACKAGE, CLASS));
        Object obj = klass.getDeclaredConstructor().newInstance();
        Method meth = klass.getDeclaredMethod(METHOD);
        meth.invoke(obj);
    }
}

这是我的图书馆

// This is defined in ReflectionLib.jar
// ReflectionLib
// └── src
//     ├── module-info.java
//     └── org
//         └── reflection
//             └── lib
//                 └── ReflectiveClass.java
//
package org.reflection.lib;

public class ReflectiveClass {

    public void doSomeWork() {
        System.out.println("::: Doing some work!");
    }
}

现在,如果我试着这样称呼它(假设所有JAR都已创建并在lib目录中可用):

java --module-path lib -m ReflectionApp/org.reflection.app.ReflectionApp

然后我得到一个Exception in thread "main" java.lang.ClassNotFoundException: org.reflection.lib.ReflectiveClass

---解决方案---

多亏了@Nicolai,我才能够通过在命令中添加--add-modules参数来运行它

⇒  java --module-path lib --add-modules ReflectionLib -m ReflectionApp/org.reflection.app.ReflectionApp
::: Doing some work!

共 (2) 个答案

  1. # 1 楼答案

    plenty of ways to make reflection work但是没有一个像模块系统之前的“it just works”方式那样直截了当。针对你的特殊问题,让我把范围缩小

    但在此之前,您必须确保模块实际进入模块图。如果初始模块不需要它,可以使用 add-modules library将其添加到图形中

    出口包装

    您写道“如果应用程序‘模块’不需要‘库’包,则库类不可访问”。假设你的意思是模块而不是,这是正确的,但不适用于这里。可访问性建立在两个方面:

    1. 两个模块之间有一条边
    2. 被访问的模块导出被访问的类型

    你没有写任何关于2的东西。但是如果module library { exports org.reflection.lib; },那么你可以自由地使用反射。原因是,当您开始使用反射API时,读取边缘会自动添加

    无法访问的类型

    现在它变得更有趣了。如果模块不导出org.reflection.lib,或者ReflectiveClass不是公共的,则上述方法不起作用。在这种情况下,你有很多选择:

    • 将类型公开并导出包(可能仅限于访问模块)
    • 打开软件包(可能仅对访问模块)或模块
    • 添加命令行选项以实现上述任一功能

    看看这篇关于reflection vs encapsulation in Java 9的文章,看看它们是如何比较的

  2. # 2 楼答案

    如果第一个模块通过module-info.java中的requires子句不依赖于第二个模块,那么第二个模块不在第一个模块依赖项的传递闭包中。因此,运行时无法观察到第二个模块,并且反射失败。在这种情况下,您可以通过 add-modules选项将模块显式添加到模块图中:

     add-modules <module-name>
    

    在您的例子中<module-name>应该被ReflectionLib模块的名称替换