【问题标题】:Why is --add-modules necessary for modules which are on the module path?为什么模块路径上的模块需要 --add-modules ?
【发布时间】:2020-10-02 02:05:14
【问题描述】:

一个例子:由于 JavaFx 从 JDK 中删除,JavaFx SDK 现在作为一组模块化 jar 分发。要编译 JavaFx 应用程序,当然必须将它们放在模块路径中:

javac -p /path/to/jars/ App.java

然而,这还不够。尝试编译会导致很多类似

的错误
sample/App.java:3: error: package javafx.application is not visible
import javafx.application.Application;
             ^
  (package javafx.application is declared in module javafx.graphics, which is not in the module graph)

要解决这个问题,我们可以使用 --add-modules 添加 javafx.graphics:

javac -p /path/to/jars/ --add-modules javafx.graphics App.java

如果我们改为向项目添加一个 module-info.java(仅包含 module ui {}),我们就没有问题。

为什么模块路径上的模块对命名模块可见,但对未命名模块不可见?

【问题讨论】:

  • 您使用哪个 Java 版本进行编译?
  • @ZhekaKozlov Java 11。Java 9 和 Java 11 处理模块有区别吗?
  • 不,至少在这种特殊情况下。我原以为可能会有一些差异,但事实证明这无关紧要。无论如何,没关系。

标签: java java-9 java-11 java-module java-platform-module-system


【解决方案1】:

+1 提出了一个非常好的问题。这里的问题是,当您编译命名模块和未命名模块时,它们的默认根模块集的计算方式非常不同。

这是来自JEP 261 的引用,解释了这种差异:

当编译器编译未命名模块中的代码,或者java 启动器被调用并加载应用程序的主类 从类路径到应用程序类的未命名模块 loader,则未命名模块的默认根模块集为 计算如下

java.se 模块是一个根,如果它存在的话。如果它不存在那么 升级模块路径或系统之间的每个 java.* 模块 导出至少一个包的模块,没有限定,是 根。

升级模块路径上或系统中的每个非 java.* 模块 至少导出一个包的模块,没有限定,是 也是一个根。

这可能看起来有点复杂,所以我已将该文本中最重要的部分加粗。另外,让我们一步一步来:

  • 你没有module-info.java,所以你的模块是一个未命名的模块。
  • java.se 存在,所以它进入了根集。
  • 您的升级模块路径为空(因为您只指定了-p 而不是--upgrade-module-path)。
  • 至少导出一个包的系统模块也进入集合。

因此,根集只有 java.se 和一些系统模块。并且没有 JavaFX 模块进入集合!

现在,当您使用module-info.java 编译时会发生什么?根集使用不同的规则计算:

否则,默认的根模块集取决于阶段:

在编译时,它通常是正在编译的模块集

由于根模块是需要 JavaFX 模块的模块,因此它们进入了模块图。

那么,如何解决这个问题?您可以通过将 JavaFX 模块放在升级模块路径上来做到这一点:

javac --upgrade-module-path /path/to/jars/ App.java

或者使用--add-modules:

javac -p /path/to/jars/ --add-modules ...

或者使用普通的旧类路径:

javac -cp /path/to/jars/ App.java

所有三个选项都应该有效。让我知道第一个选项是否真的有效,因为我没有尝试过。

【讨论】:

  • 正是我想要的!有时间我会看看升级模块路径。
猜你喜欢
  • 2019-09-29
  • 1970-01-01
  • 1970-01-01
  • 2019-01-15
  • 1970-01-01
  • 2020-05-31
  • 1970-01-01
  • 1970-01-01
  • 2019-09-02
相关资源
最近更新 更多