需要和需要Java 9中的传递语句之间的区别是什么?

时间:2017-09-30 11:53:56

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

模块声明中 需要 需要传递 模块语句的区别是什么?<登记/>
例如:

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

6 个答案:

答案 0 :(得分:62)

可读性回顾

如果模块 bar requires模块饮用,那么模块系统......

  • 强制执行饮料(称为可靠配置
  • 允许 bar 阅读饮料(名为readability
  • 允许 bar 中的代码访问 drink 中导出的包中的公共类(名为accessibility

如果 bar requires transitive drink - 饮料必须存在,可以阅读和访问,则完全相同。事实上,对于 bar drink transitive关键字不会改变任何内容。

隐含的可读性

模块取决于 bar 是受transitive影响的模块:任何读取 bar 的模块也可以读取。换句话说, drink 的可读性是暗示(这就是为什么这称为implied readability)。结果是客户可以访问饮料的类型。

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

用例

但为什么呢?想象一下,你有一个模块,其公共API接受或返回另一个模块的类型。假设 bar 模块公开返回Drink的实例,这是来自饮料模块的界面:

// in module _bar_
public class Bar {

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

}

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

模块系统抱怨客户没有读取饮料,因此无法访问Drink。要解决此问题,客户还必须依赖饮料。真是个琐事!你不能马上使用的酒吧是多么无用?

customer requires bar requires drink - but how does customer read drink?

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

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

答案 1 :(得分:6)

两者之间的主要区别在于从属模块的访问权限。

  

如果一个模块导出包含其签名类型的包   指的是第二个模块中的包然后声明的   第一个模块应该包括requires transitive依赖   第二。这个 将确保依赖于其他模块   第一个模块将自动读取第二个模块 ,   因此,访问该模块导出的包中的所有类型。

因此,请告诉您的用例: -

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

〜&GT;依赖于foo模块的任何模块都将自动读取java.compiler模块

〜&GT;另一方面,要访问模块java.base,他们必须再次指定requires子句。

module bar {
    requires foo; // java.compiler is available to read
    requires java.base; // still required
}

答案 2 :(得分:5)

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

Quoting line

  

'require'指令(不论'传递')表达了这一点   一个模块依赖于其他模块。 的效果    'transitive'修饰符会导致其他模块依赖   另一个模块 。如果模块M'需要传递N',那么不仅如此   M取决于N,但依赖于M的任何模块也依赖于   N.这允许M被重构以便其部分或全部内容   可以移动到新模块N而不破坏具有的模块   '需要M'指令。

简而言之:

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

requires transitive - 其他模块隐含地取决于其他模块。例如:,如果M模块依赖于N,而其他模块P依赖于M.那么,它也隐含地依赖于N.

答案 3 :(得分:2)

尼古拉已经详细解释过。我只是在这里给出一个JDK代码的具体示例。考虑jdk.scripting.nashorn模块。该模块的模块信息如下:

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模块在​​jdk.scripting.api.scripting包中自己的API接受/返回javax.script模块的java.scripting包中的类型。所以jdk.scripting.nashorn告诉JMPS,任何依赖于jdk.scripting.nashorn的模块都会自动依赖于java.scripting模块!

现在,相同的jdk.scripting.nashorn模块使用以下行:

    requires jdk.dynalink;

另一个模块jdk.dynalink。这是因为jdk.scripting.nashorn模块中导出的包的 none (&#34; API&#34;)使用了jdk.dynalink模块中的类型。 jdk.scripting.nashorn对jdk.dynalink的使用纯粹是一个实现细节。

答案 4 :(得分:1)

Java 9 Java语言规范以非常简单的术语解释它。来自Module Dependences的部分:

  

requires指令指定当前模块具有依赖关系的模块的名称。

     

...

     

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

换句话说:

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

答案 5 :(得分:0)

术语辅助功能含糊不清:您可以访问对象而无需访问其类型。如果一个对象的类型为T,它位于一个未导出的包中,并且一个“导出的”代码有一个方法返回一个T ...那么当调用这个方法时,你得到一个关于这个T对象的句柄(你可以调用任何与代码已知类型相关的方法。

可读性也不明确:它并不意味着你的ClassLoader总是无法加载(未导出的)T类。

相关问题