模块声明中的requires和requires 传递模块语句有什么区别?
例如:
module foo {
requires java.base;
requires transitive java.compiler;
}
模块声明中的requires和requires 传递模块语句有什么区别?
例如:
module foo {
requires java.base;
requires transitive java.compiler;
}
如果模块酒吧 requires
模块饮料,那么模块系统...
如果酒吧 requires transitive drink
-饮料必须存在,可以读取和访问,则会发生完全相同的情况。事实上,对于bar和Drink,transitive
关键字并没有改变任何东西。
依赖于bar的模块会受到以下影响transitive
: 任何读取bar的模块也可以读取drink。换句话说,饮料的可读性是隐含的(这就是为什么这被称为隐含可读性)。结果是客户可以访问饮料的类型。
因此,如果bar requires transitive drink
和customer 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
就足够了。正如它应该。
两者之间的主要区别在于依赖模块从一个到另一个的访问。
如果一个模块导出的包包含的类型的签名引用第二个模块中的包,则第一个模块的声明应包括
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”指令(与“传递”无关)表示一个模块依赖于其他模块。'transitive' 修饰符的效果 是使其他模块也依赖于其他模块。如果模块 M '需要传递 N',那么不仅 M 依赖于 N,而且任何依赖于 M 的模块也依赖于 N。这允许重构 M 以便其部分或全部内容可以移动到新的模块 N 不破坏具有“需要 M”指令的模块。
简而言之 :
requires
- M 模块依赖于其他模块 N。
requires transitive
- 附加模块隐式依赖于其他模块。例如:,如果 M 模块依赖于 N,而其他模块 P 依赖于 M。那么,它也隐式依赖于 N。
尼古拉已经详细解释过了。我只是从 JDK 代码中给出一个具体的例子。考虑 jdk.scripting.nashorn 模块。该模块的module-info如下:
它有这一行:
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 的使用纯粹是一个实现细节。
Java 9 的 Java 语言规范用非常简单的术语解释了它。从模块依赖部分:
该
requires
指令指定当前模块所依赖的模块的名称。...
关键字后面
requires
可以跟修饰符。这会导致当前模块隐含声明依赖于指令指定的模块的任何模块。transitive
requires
requires transitive
换句话说:
requires
模块 Y,requires transitive
模块 Z,requires
模块 Z。可访问性一词是模棱两可的:您可以访问对象而不访问它们的类型。如果一个对象的类型 T 位于未导出的包中,并且如果“导出”代码有一个返回 T 的方法......那么当调用此方法时,您将获得该 T 对象的句柄(并且您可以在其上调用与您的代码已知的任何类型有关的任何方法)。
可读性也是模棱两可的:这并不意味着您的 ClassLoader 将始终无法加载(未导出的)T 类。
上面已经解释了需要和需要传递之间的区别,因此我只会添加需要传递的效果
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