在JDK 9的javac中,是否可以混合使用--class-path和--module-path?

35
当我编译一个依赖于先前编译的其他模块的模块时,我必须指定 --module-path <directory> 选项。这使我依赖的模块可见。
但同时,我也想让一些非模块化的Jar文件可见。然而,如果我不将它们变成自动模块,只是在 --module-path <directory> 旁边指定 --class-path some.jar,那么 javac 似乎会忽略类路径并抛出“找不到包 yyy”和其他“未找到”错误。
我可以理解同时在(编译)时间使用--class-path--module-path 是不合法的,但 javac 没有以任何方式警告我。

可以混合使用这两种方法,你能分享一个最小的示例让我们验证一下吗? - Ahmed Masud
我可以理解在编译时同时使用 --class-path 和 --module-path 是非法的,但是为什么呢? - Naman
8
混合编译是完全合法的。但是,模块化的 JAR 包不能引用类路径上的非模块化的 JAR 包。自动模块(模块路径上的非模块化 JAR 包)充当桥梁:模块化的 JAR 包可以引用它们,而自动模块可以读取类路径。 - Michael Easter
2个回答

49

您可以同时使用类路径和模块路径,但需要考虑几个细节。

依赖模块路径 ~> 类路径

显式模块(在模块路径上具有模块描述符的JAR)无法读取未命名模块(类路径上的JAR),这是有意为之的,以防止模块化JAR依赖于“类路径的混乱”。

由于模块必须要求所有依赖项,并且这些依赖项只能由其他命名模块(即不在类路径上的JAR)满足,因此模块化JAR的所有依赖项都必须放置在模块路径上。是的,甚至包括非模块化的JAR,它们将被转换为自动模块

有趣的是,自动模块可以读取未命名模块,因此它们的依赖项可以放在类路径上。

依赖类路径 ~> 模块路径

如果您编译非模块化代码或从非模块化JAR启动应用程序,则仍然使用模块系统,并且由于非模块化代码不表达任何依赖关系,因此它将不会从模块路径解析模块。

因此,如果非模块化代码依赖于模块路径上的构件,则需要使用--add-modules选项手动添加它们。不一定需要添加所有依赖项,只需添加您直接依赖的那些(模块系统将引入传递依赖项),或者您可以使用ALL-MODULE-PATH(请检查链接的帖子,它会更详细地解释这一点)。


9
Nicolai的回答是正确的,但我认为可以进一步指出--add-modules选项可能需要被使用,以确保类路径代码所需的模块被解析。原始问题询问为什么javac失败,我假设这是因为他/她正在编译具有对模块路径上的模块中的类的引用的类路径代码,并且只需要使用--add-modules来确保模块已被解析。 - Alan Bateman
@AlanBateman 我尝试在编译过程中混合使用-classpath和--module-path,即使我使用了--add-modules,但它仍然失败了。 javac -cp lib\* --module-path modules --add-modules simpleModule -d out @classes.txt 其中:lib是我的jar文件夹,我想在未命名模块中使用它;modules-包含一个文件夹(文件夹名称=simpleModule),里面有module-info.java;@classes.txt-列出要编译的类(包括来自modules文件夹的模块化类);simpleModule-来自“modules”文件夹的模块名称。运行此命令后,我得到了“package does not exist”的错误,这是由于lib目录中的jar文件。 - David
@Nicolai没有帮助。提出了一个问题 https://dev59.com/iarka4cB1Zd3GeqPZi6m - David
你可能已经发现了这一点,而且我可能误解了评论,但自动模块 必须 是 jars。一个简单的文件夹是不起作用的。 - Toby Eggitt
如何在Gradle项目中实现? - Kingson wu
显示剩余2条评论

11

我认为同时使用 --classpath--module-path 选项是不违规的。即使在没有明确指定类路径的情况下,也可以同时使用两者,因为它会默认为当前目录。

来自 javac -help 消息和 javac 工具文档的详细信息 -

--module-path <path>, -p <path>

指定应用程序模块所在的位置

--class-path <path>, -classpath <path>, -cp <path>

指定用户类文件和注解处理器的位置。

 

如果未指定--class-path-classpath-cp,则用户类路径为当前目录


编辑:感谢@MouseEvent指出问题中可能遗漏的部分

 

但是如果不将它们设置为自动模块,只需在--module-path旁边指定--class-path some.jar,则javac似乎会忽略claspath并引发“找不到包yyy”和其他“找不到”错误。

如果不将它们设置为自动模块,则会被视为模块系统的未命名模块,并且 -

 

实际上,具有名称的模块甚至不能声明对未命名模块的依赖关系。这个限制是有意的,因为允许具有名称的模块依赖于类路径的任意内容会使可靠的配置变得不可能。

此外,未命名模块导出其所有包,因此自动模块中的代码将能够访问从类路径加载的任何公共类型。

但是,自动模块使用类路径中的类型不能将这些类型公开给依赖于它的显式模块,因为显式模块无法声明对未命名模块的依赖关系。

 

如果显式模块com.foo.app中的代码引用com.foo.bar中的公共类型的签名引用仍然在类路径上的一个JAR文件中的类型,则com.foo.app中的代码将无法访问该类型,因为com.foo.app不能依赖于未命名模块。

可以通过暂时将com.foo.app视为自动模块来解决此问题,以便其代码可以访问来自类路径的类型,直到将类路径上的相关JAR文件视为自动模块或转换为显式模块的时间到来。


@MouseEvent 嗯,那是真的。我之前可能错过了问题中的那部分内容,只回答了标题。已经编辑并包含进去了。谢谢 :) - Naman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接