2

从项目Jigsaw的快速入门教程中,似乎 module-info.java 进入了具有模块名称的目录,例如,对于包含类 MyClass 的模块 my.module:

bin/
    my.module/
        module-info.class
        my/
            module/
                MyClass.class

然后,仍然按照教程,在调用 MyClass 时(假设它有一个method),模块路径选项被赋予bin目录:

java -p path/to/bin -m my.module/my.module.MyClass

到目前为止,一切都很好。

但是,如果我写它也可以:

java -p path/to/bin/my.module -m my.module/my.module.MyClass

而且我不明白为什么两者都有效。

如果bin包含两个模块,则没有区别:如果两个目录都在模块路径中,则第二个版本仍然有效(如果仅bin在模块路径中,它也有效,如教程中所述)。


现在,当我尝试使用 Java 9 模块使用 Eclipse 创建 Maven 项目时,module-info.java 位于src/man/java目录中,同样 module-info.class 位于target/classes. 所以现在包含 module-info.class 文件的目录与模块的名称没有关系。

并且target/classes也在模块路径中(当我检查构建配置时)。这类似于上面的第二种情况,使用java -p path/to/bin/my.module -m my.module/my.module.MyClass. 那么,显然,Java 仅使用 module-info.class 的内容来发现模块名称,而目录名称是任意的?

但是,在第一种情况下,当我写 时java -p path/to/bin -m my.module/my.module.MyClass,这意味着 Java 将在模块路径中的目录中查找目录。

我觉得我错过了一些重要的东西。Java 在模块路径中的目录中查找模块的方式是否有明确的解释?什么真正指定了一个模块?(我的印象是:不是目录,只有module-info.java)。


让我更加困惑的是:Oracle 文档指出:

--module-path 模块路径... 或 -p 模块路径

分号 (;) 分隔的目录列表,其中每个目录都是模块目录。

但显然这不是全部,至少不是 Eclipse 使用此选项的方式。


注意:我见过这个问题,但它并没有真正帮助:一个答案说 module-info.java 进入 src/java/,另一个说它进入一个名为模块名称的目录。显然两者都是正确的,但他们没有解释原因,并且存在明显的矛盾。

4

1 回答 1

1

从以下文档java.lang.module.ModuleFinder#of(Path...)

返回一个模块查找器,它通过搜索一系列目录和/或打包模块来定位文件系统上的模块。给定数组中的每个元素都是以下之一:

  1. 模块目录的路径。
  2. 展开模块的顶级目录的路径。
  3. 打包模块的路径。

模块查找器通过按数组索引顺序搜索每个目录、展开的模块或打包的模块来定位模块。它找到具有给定名称的模块的第一次出现,并忽略序列中稍后出现的具有该名称的其他模块。

如果元素是模块目录的路径,则目录中的每个条目都是打包的模块或分解模块的顶级目录[强调添加]。如果一个目录包含多个具有相同名称的模块,则会发生错误。如果一个元素是一个目录的路径,并且该目录包含一个名为 的文件module-info.class,则该目录将被视为展开的模块,而不是模块的目录[强调添加]。

此方法返回的模块查找器支持打包为 JAR 文件的模块。module-info.class在其顶级目录中或在多版本JAR文件的版本化条目中具有 的JAR 文件是模块化 JAR 文件,因此定义了显式模块。[...]

[...]

  • 当您使用--module-path path/to/bin路径条目时,将被视为模块的目录。这是因为目录(即顶级目录)中没有module-info.class文件。bin

    • 据我所知,模块目录中的任何展开的模块都不需要具有名称与模块名称匹配的顶级目录。这只是一个约定。换句话说,您可以将my.module目录重命名为您想要的任何名称;ModuleFinder只需查看目录以查看是否存在文件module-info.class
  • 当您使用--module-path path/to/bin/my.module路径条目时,将被视为展开的模块。这是因为目录(即顶级目录)module-info.class中存在一个文件。my.module

    • 使用 Maven 等构建工具时也是如此。该target/classes目录是一个展开的模块,因为该module-info.class文件存在于顶级目录中。

不幸的是,我找不到任何说明上述ModuleFinder实现在执行时保证在内部使用的内容java。但是,很可能以上是所使用的。

于 2019-11-23T07:44:11.300 回答