Java 9 中的 requires 和 requires 传递语句有什么区别?

What's the difference between requires and requires transitive statements in Java 9?

requiresrequires transitive[=有什么区别21=] 模块声明中的模块语句?

例如:

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

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

If one module exports a package containing a type whose signature refers to a package in a second module then the declaration of the first module should include a requires transitive dependence upon the second. This will ensure that other modules that depend upon the first module will automatically be able to read the second module and, hence, access all the types in that module’s exported packages.


所以让我们说一下您的用例:-

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
}

requires描述了模块之间相互依赖的解析过程。

Quoting line

A 'requires' directive (irrespective of 'transitive') expresses that one module depends on some other module. The effect of the 'transitive' modifier is to cause additional modules to also depend on the other module. If module M 'requires transitive N', then not only does M depend on N, but any module that depends on M also depends on N. This allows M to be refactored so that some or all of its content can be moved to a new module N without breaking modules that have a 'requires M' directive.

简而言之:

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

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

可读性回顾

如果模块barrequires模块drink,那么模块系统...

  • 强制存在drink(称为可靠配置
  • 允许bar阅读drink(调用readability
  • 允许 bar 中的代码访问 public 类 drink 中的导出包(称为 accessibility)

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

隐含的可读性

依赖于bar的模块transitive影响:任何读取[=54的模块=]bar也可以读作drink。换句话说,drink 的可读性是 implied(这就是为什么它被称为 implied readability)。结果是 customer 可以访问 drink 的类型。

因此,如果 bar requires transitive drinkcustomer requires bar,那么 customer 可以阅读 drink,即使它不阅读明确依赖它。

用例

但是为什么呢?假设您有一个模块,其 public API 接受或 returns 另一个模块的类型。假设 bar 模块 publicly returns 个实例 Drink,一个来自 drink 模块的接口:

// in module _bar_
public class Bar {

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

}

在此示例中,bar 使用 drink 的常规 requires。现在说,customer 依赖于 bar,所以它的所有代码都可以调用 Bar::buyDrink。但是当它发生时会发生什么?

模块系统抱怨 customer 没有读取 drink,因此无法访问 Drink。要解决这个问题,customer 还必须依赖 drink。多么苦差事!不能马上用的酒吧有多无用?

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

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

Nicolai已经详细解释了。我只是在此处给出 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.nashorn module's own API in jdk.scripting.api.scripting package accepts/returns types from javax.script package of the java.scripting模块。所以 jdk.scripting.nashorn 告诉 JMPS 任何依赖 jdk.scripting.nashorn 的模块也会自动依赖 java.scripting 模块!

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

    requires jdk.dynalink;

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

Java Java 9 的语言规范用非常简单的术语对其进行了解释。来自 Module Dependences 部分:

The requires directive specifies the name of a module on which the current module has a dependence.

...

The requires keyword may be followed by the modifier transitive. This causes any module which requires the current module to have an implicitly declared dependence on the module specified by the requires transitive directive.

换句话说:

  • 如果模块 X requires 模块 Y,
  • 和模块 Y requires transitive 模块 Z,
  • 然后模块 X 也(隐含地)requires 模块 Z。

可访问性 一词含糊不清:您可以访问对象而无需访问其类型。如果一个对象是 T 类型的对象,它位于未导出的包中,并且如果 "exported" 代码具有 returns 一个 T ... 的方法,那么在调用此方法时,您将获得此句柄T 对象(您可以在其上调用属于您的代码已知的任何类型的任何方法)。

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

requires 和 requires transitive 的区别在上面已经解释过了,所以我只添加 requires transitive 的效果

  • if (module m requires transitive n) && (module L requires m) then module L cannot be compile or execute without access to module n

  • if (module m requires transitive n) && (module L requires both m and n) then module L doesn't need to explicitly declare requires for n