92

模块声明中的requiresrequires 传递模块语句有什么区别?

例如:

module foo {
    requires java.base;
    requires transitive java.compiler;
}
4

7 回答 7

153

可读性回顾

如果模块酒吧 requires模块饮料,那么模块系统...

  • 强制存在饮料(称为可靠配置
  • 允许酒吧阅读饮料(称为可读性
  • 允许bar中的代码访问 Drink 中导出包中的公共类称为辅助功能

如果酒吧 requires transitive drink-饮料必须存在,可以读取和访问,则会发生完全相同的情况。事实上,对于barDrinktransitive关键字并没有改变任何东西。

隐含的可读性

依赖于bar的模块会受到以下影响transitive: 任何读取bar的模块也可以读取drink。换句话说,饮料的可读性是隐含的(这就是为什么这被称为隐含可读性)。结果是客户可以访问饮料的类型。

因此,如果bar requires transitive drinkcustomer requires bar,则客户可以读取饮料,即使它没有明确依赖它。

用例

但为什么?假设您有一个模块,其公共 API 接受或返回另一个模块的类型。假设bar模块公开返回 的实例Drink,一个来自饮料模块的接口:

// in module _bar_
public class Bar {

    // `Drink` comes from the module _drink_,
    // which _bar_ requires
    public Drink buyDrink() { /* ... */ }

}

在此示例中,bar使用正则requires表示Drink。现在说,客户依赖bar,所以它的所有代码都可以调用Bar::buyDrink。但是当它发生时会发生什么?

模块系统抱怨客户不阅读饮料,因此无法访问Drink。要解决这个问题,客户还必须依赖饮料。真是个苦差事!不能立即使用的酒吧有多没用?

客户要求酒吧要求饮料 - 但客户如何阅读饮料?

出于这个原因,引入了隐含的可读性:使在其自己的公共 API 中使用另一个模块类型的模块立即可用,而无需调用者查找并要求所有涉及的模块。

因此bar requires transitive drink,如果客户可以开始购买饮料而无需require drink-require bar就足够了。正如它应该。

于 2017-09-30T15:11:06.817 回答
16

两者之间的主要区别在于依赖模块从一个到另一个的访问。

如果一个模块导出的包包含的类型的签名引用第二个模块中的包,则第一个模块的声明应包括requires transitive对第二个模块的依赖。这将确保依赖于第一个模块的其他模块将能够自动读取第二个模块,从而访问该模块导出包中的所有类型。


因此,假设您的用例:-

module foo {
    requires java.base;
    requires transitive java.compiler;
}

~> 任何依赖于该模块的foo模块都会自动读取该java.compiler模块

~> 另一方面,要访问模块java.base,他们必须再次指定一个requires子句。

module bar {
    requires foo; // java.compiler is available to read
    requires java.base; // still required
}
于 2017-09-30T12:00:09.430 回答
7

requires描述了解决模块如何相互依赖的过程。

报价行

“requires”指令(与“传递”无关)表示一个模块依赖于其他模块。'transitive' 修饰符的效果 是使其他模块也依赖于其他模块。如果模块 M '需要传递 N',那么不仅 M 依赖于 N,而且任何依赖于 M 的模块也依赖于 N。这允许重构 M 以便其部分或全部内容可以移动到新的模块 N 不破坏具有“需要 M”指令的模块。

简而言之 :

requires- M 模块依赖于其他模块 N。

requires transitive- 附加模块隐式依赖于其他模块。例如:,如果 M 模块依赖于 N,而其他模块 P 依赖于 M。那么,它也隐式依赖于 N。

于 2017-09-30T12:07:31.883 回答
2

尼古拉已经详细解释过了。我只是从 JDK 代码中给出一个具体的例子。考虑 jdk.scripting.nashorn 模块。该模块的module-info如下:

http://hg.openjdk.java.net/jdk9/dev/nashorn/file/17cc754c8936/src/jdk.scripting.nashorn/share/classes/module-info.java

它有这一行:

requires transitive java.scripting;

这是因为jdk.scripting.api.scripting包中jdk.scripting.nashorn模块自己的 API接受/返回来自java.scripting模块的javax.script包的类型。所以 jdk.scripting.nashorn 告诉 JMPS 任何依赖于 jdk.scripting.nashorn 的模块也会自动依赖于 java.scripting 模块!

现在,同一个 jdk.scripting.nashorn 模块使用这一行:

    requires jdk.dynalink;

对于另一个模块jdk.dynalink。这是因为来自jdk.scripting.nashorn模块的导出包(“API”)都没有使用来自 jdk.dynalink 模块的类型。jdk.scripting.nashorn 对 jdk.dynalink 的使用纯粹是一个实现细节。

于 2017-09-30T16:01:38.207 回答
2

Java 9 的 Java 语言规范用非常简单的术语解释了它。从模块依赖部分:

requires指令指定当前模块所依赖的模块的名称。

...

关键字后面requires可以跟修饰符。这会导致当前模块隐含声明依赖于指令指定的模块的任何模块。transitiverequiresrequires transitive

换句话说:

  • 如果模块 Xrequires模块 Y,
  • 和模块 Yrequires transitive模块 Z,
  • 然后模块 X 也(隐式)requires模块 Z。
于 2017-09-30T17:59:46.880 回答
0

可访问性一词是模棱两可的:您可以访问对象而不访问它们的类型。如果一个对象的类型 T 位于未导出的包中,并且如果“导出”代码有一个返回 T 的方法......那么当调用此方法时,您将获得该 T 对象的句柄(并且您可以在其上调用与您的代码已知的任何类型有关的任何方法)。

可读性也是模棱两可的:这并不意味着您的 ClassLoader 将始终无法加载(未导出的)T 类。

于 2018-02-14T11:10:32.753 回答
0

上面已经解释了需要和需要传递之间的区别,因此我只会添加需要传递的效果

  • if (module m requires transitive n) && (module L requires m) then module L不能在没有访问模块n的情况下被编译或执行

  • if (module m requires transitive n) && (module L requires both m and n) then module L不需要显式声明对n的require

于 2022-01-20T19:41:22.777 回答