为什么未模块化的JAR可以访问由模块化JAR打包的非公开?

时间:2017-11-17 09:00:46

标签: java java-9 java-module module-info

我正在使用IntelliJ中的Java 9: 我创建了4个模块(所有模块都依赖于module1):

  1. module1:导出包pkg1并将pkg2导出到模块2。
  2. module2:需要module1并且能够访问这两个包
  3. module3:需要module1且只能访问pkg1
  4. module4:没有module-info.class,能够访问module1的两个软件包
  5. 我认为自动模块应该要求所有暴露的包装而不是未暴露的包装。

    我不明白封装的重点是什么,如果它仅适用于明确模块化的JAR。

    我错过了什么?

3 个答案:

答案 0 :(得分:3)

在您的示例 module4 中,将能够访问pkg2。自动模块读取所有其他模块(因为它们不能表示依赖关系),但rules to access types不会更改,因此只能访问导出包中的公共类型。

基于您的引用的一些背景知识:

  

我认为自动模块应该要求所有暴露的包装而不是未暴露的包装。

显式模块(即非自动模块)需要其他模块。在运行时,那些需要指令的是turned into readability edges。但它们并不是这些边缘的唯一来源:对于自动模块,边缘被添加到已解析的每个模块中(即将其放入可读性图中)。

所以当你说“自动模块应该需要所有暴露的软件包”时,会有一些错误,可能会在翻译中丢失,但我仍然想澄清一下。该句子应该代之以“自动模块读取所有(已解决的)模块”。

在这个阶段,没有人谈论可访问性和包。这是下一步,这里自动模块并不特殊,因此无法访问内部API。

答案 1 :(得分:2)

由于模块系统中的automatic modules没有模块描述符(module-info.class),因此没有好的方法来确定自动模块可能依赖哪些其他模块。

因此,在解析模块图之后,自动模块 可以读取所有其他命名模块,无论是自动还是显式。

因此,在您的情况下,作为自动模块的module4能够读取显式模块module1

accessibility as defined in the module system(由我绘制的相似性)如下所示:如果在不同模块中定义了两种类型STT为{{1}然后,public中的代码可以访问S if:

  • S的模块读取T的模块,(T读取module4)和

  • T的模块导出T的包。 (module1module1导出到需要pckg1module1pckg2的所有模块

  

跨模块边界引用的类型,无法访问   这种方式与私有方法或字段的方式不同   不可用:任何使用它的尝试都会导致报告错误   编译器,或Java抛出的module2   虚拟机,或者被IllegalAccessError抛出的虚拟机   反射运行时API。

     

因此,即使将类型声明为public,   如果它的包没有在其模块的声明中导出那么   它只能被该模块中的代码访问

答案 2 :(得分:0)

为了消除IntelliJ逻辑,我从我的模块(1,2和4)中构建了3个JAR,并在命令行中使用java开始使用它们。

当我尝试仅使用-cp选项执行代码时,它具有相同的行为,即module4能够访问pkg2 - >这让我得出结论,如果IntelliJ模块中没有module-info.java文件,则使用类路径。

这是棘手的部分: 我使用了--list-modules选项来确保module4的自动名称是module4。 然后我执行了类似的事情:

java -p "<module1 path>;<module4 path>" -m module4/<MainClass>

我在pkg1(导出的包)的类上有一个ClassNotFoundException。

如果我执行:

java -p "<module1 path>;<module2 path>" -m module2/<MainClass>

然后一切正常。

因此,如果我们想要使用模块路径,主类必须来自模块化的JAR。

看起来,自动JAR是为了向后兼容,因此我们可以将它们用作新模块的依赖项。

但是如果想要使用模块路径执行模块,Java假定我们正在执行的JAR是一个模块化的JAR,否则我们应该继续使用类路径。

换句话说,如果我们使用-p(modulepath)选项执行未模块化的JAR,它将不需要路径中的其他模块。

所有这些结论都来自于Java,有人能指出我背后的理论部分吗?