需求和需要模块声明中的传递模块语句有什么区别? 例如:
module foo {
requires java.base;
requires transitive java.compiler;
}
如果模块条requires
模块喝,那么模块系统......
如果bar requires transitive drink
- 饮料必须存在,可以阅读和访问,则完全相同。事实上,对于酒吧和饮料,transitive
关键字不会改变任何东西。
依赖于栏的模块是受transitive
影响的模块:任何读取栏的模块也可以读取饮料。换句话说,暗示了饮料的可读性(这就是为什么这被称为implied readability)。结果是客户可以访问饮料类型。
因此,如果bar requires transitive drink
和customer 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
。为了解决这个问题,顾客也必须依赖饮料。真是个琐事!你不能马上使用的酒吧是多么无用?
出于这个原因,引入了隐含的可读性:使模块在其自己的公共API中使用另一个模块的类型立即可用,而无需调用者追捕并需要所有涉及的模块。
因此,如果bar requires transitive drink
,客户可以开始购买饮料而无需require drink
- require bar
就足够了。正如它应该。
两者之间的主要区别在于从属模块从一个模块到另一个模块的访问。
如果一个模块导出包含其签名引用第二个模块中的包的类型的包,则第一个模块的声明应包括
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
}
requires
描述了关于模块如何相互依赖的解决过程。
'requires'指令(不论'传递')表示一个模块依赖于某个其他模块。 “传递”修饰符的作用是使其他模块也依赖于其他模块。如果模块M'需要传递N',那么M不仅依赖于N,而且依赖于M的任何模块也依赖于N.这允许M被重构以使其部分或全部内容可以移动到新的模块N没有破坏具有'requires M'指令的模块。
简而言之 :
requires
- M模块依赖于其他一些模块N.
requires transitive
- 附加模块隐含地取决于其他模块。例如:,如果M模块依赖于N,而其他模块P依赖于M.那么,它也隐含地依赖于N.
尼古拉已经详细解释过。我只是在这里给出一个JDK代码的具体示例。考虑jdk.scripting.nashorn模块。该模块的模块信息如下:
它有这条线:
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的使用纯粹是一个实现细节。
Java 9 Java语言规范以非常简单的术语解释了它。从Module Dependences部分:
requires
指令指定当前模块具有依赖关系的模块的名称。...
requires
关键字后跟修饰符transitive
。这导致requires
当前模块的任何模块具有隐式声明的对requires transitive
指令指定的模块的依赖性。
换一种说法:
requires
模块Y,requires transitive
模块Z,requires
模块Z.术语可访问性不明确:您可以访问对象而无需访问其类型。如果一个对象的类型为T,它位于一个未导出的包中,并且一个“导出的”代码有一个方法返回一个T ...那么当调用这个方法时,你得到一个关于这个T对象的句柄(你可以调用与您的代码已知的任何类型相关的任何方法。
可读性也不明确:它并不意味着你的ClassLoader总是无法加载(未导出的)T类。