11

我是 Java 9 的新手,正在观看 YouTube 上 Java 的模块化视频讲座。他们提到了模块化的 3 个好处 - 1. 没有丢失的依赖项 2. 没有循环依赖项 3. 没有拆分包。

据我了解拆分包是假设一个应用程序依赖于多个依赖项,假设包 abc.pqr.xyz 存在于 1 个以上的 jar 中。然后有可能该包中的某些类将从 jar1 中使用,而其他类则从 jar2 中使用。这可能会在运行时导致一些难以调试的问题。

视频说模块化解决了这个问题。但这就是我想要理解的?

假设有 test.module1 具有以下模块信息 -

module test.module1{
exports abc.pqr.xyz;
}

另一个具有以下模块信息的模块2-

module test.module2{
 exports abc.pqr.xyz;
}

现在假设在我的应用程序中我添加了这两个模块的依赖项-

module test.myapp{
 requires test.module1;
 requires test.module2;
}

现在我再次有 2 个模块化依赖项,其中一些类可能会出现在这两个模块中。那么在运行时它将如何从哪个模块中获取类定义呢?Java 9 如何避免拆分包问题?

4

2 回答 2

9

对于问题中描述的场景,您将开始面临错误阅读:

模块从两者中test.myapp读取包test.module1test.module2

模块系统状态中模块的可读性详细说明了模块的使用,如下所示,您的用例应该会感兴趣(强调我的):

模块图中定义的可读性关系是可靠配置的基础:模块系统确保

  • 每个依赖都由另一个模块完成
  • 模块图是非循环的
  • 每个模块最多读取一个定义给定包的模块
  • 并且定义同名包的模块不会相互干扰

在模块系统中暗示相同的好处也很详细

可靠的配置不仅更可靠;它也可以更快。当模块中的代码引用包中的类型时,则保证该包被定义在该模块中或恰好在该模块读取的模块之一中。

因此,在查找特定类型的定义时,无需在多个模块中搜索它,或者更糟的是,沿着整个类路径搜索。


也就是说,当前实施的解决方案是

  • 如果模块test.module1test.module2显式模块,您可以选择在其中任何一个中abc.pqr.xyz实现包,或者 将其从两者中拉出到您自己的单独模块中,此后可以在其客户端中用作独立模块。test.mergeModule

  • 如果这些(或其中任何一个)是自动模块,您可以使用扩展至类路径的桥,让此类 jar 保留在类路径中并被视为未命名模块,默认情况下应导出其所有包。同时,任何自动模块在读取每个其他命名模块时也会读取未命名模块

    再次引用文档并举例说明,以便您可以与您的问题相关联:

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

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

于 2018-08-13T18:58:08.253 回答
7

Java 模块系统通过在 JVM 启动时拒绝这种场景来解决拆分包问题。当 JVM 启动时,它会立即开始解析模块图,当它在test.myapp's 的模块路径中遇到两个模块时,JVM 会抛出一个错误,指示test.module1test.module2正在尝试导出相同的包。

于 2018-08-13T18:09:24.573 回答