需求和需要Java 9中的传递语句有什么区别?

问题描述 投票:45回答:6

需求和需要模块声明中的传递模块语句有什么区别? 例如:

module foo {
    requires java.base;
    requires transitive java.compiler;
}
java java-9 java-module requires module-info
6个回答
63
投票

可读性回顾

如果模块条requires模块喝,那么模块系统......

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

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

隐含的可读性

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

因此,如果bar requires transitive drinkcustomer requires bar,那么顾客可以阅读饮料,即使它没有明确依赖它。

用例

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

// in module _bar_
public class Bar {

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

}

在这个例子中,酒吧使用常规的requires饮用。现在说,客户依赖于bar,所以它的所有代码都可以调用Bar::buyDrink。但是当它发生时会发生什么?

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

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

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

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


6
投票

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

如果一个模块导出包含其签名引用第二个模块中的包的类型的包,则第一个模块的声明应包括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
}

5
投票

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

Quoting line

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

简而言之 :

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

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


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模块中没有导出的包(“API”)使用jdk.dynalink模块中的类型。 jdk.scripting.nashorn对jdk.dynalink的使用纯粹是一个实现细节。


2
投票

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

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

...

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

换一种说法:

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

0
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.