为什么 Java 9 不简单地将 class 路径上的所有 JAR 转换为自动模块?

Why Java 9 does not simply turn all JARs on the class path into automatic modules?

为了理解我们的类别:

类路径中的所有 类 和 jar 都将成为未命名模块的一部分。但为什么这是我们需要的?与自动模块相比,优势在哪里?我可以 "require" 那些该死的遗留罐子,使它们成为一个自动模块。我没有把所有东西都包括在内吗?

至少有两个原因:

  • 就像常规模块一样,自动模块对模块系统的某些检查是可疑的,例如。 not splitting packages。由于 class 路径上的 JAR 可以(偶尔会这样做)拆分包,因此对它们进行检查将是向后不兼容的,并且会破坏许多应用程序。
  • 未命名模块可以读取所有平台模块,而自动模块只能读取那些进入模块图中的模块。这意味着需要 java.desktop 模块(例如)的 JAR 将从 class 路径工作,但不会从模块图中工作,除非 java.desktop 也进入图表(通过依赖关系或 --add-modules)。

我现在没有时间检查第二个,但这就是 the State of the Module system 所说的:

After a module graph is resolved, therefore, an automatic module is made to read every other named module, whether automatic or explicit

解决方案适用于声明的依赖项,并且自动模块声明 none。

除了接受的答案中列出的项目之外,还有一个区别:未命名模块可以访问 Java 附带的所有模块包,即使它们没有导出。 只要 class 是 public,访问就可以工作 - 和以前一样 Java 9. 但是一旦模块路径中的 jar 是 运行,它将能够仅访问导出的包。

例如,如果某些 .jar 有此代码:

com.sun.jmx.remote.internal.ArrayQueue c = new com.sun.jmx.remote.internal.ArrayQueue(10);

放置在 class 路径时,它通常 运行 没有任何警告,但是当 运行 来自模块路径(作为自动模块)时,它将在 运行 处失败时间:

Exception in thread "main" java.lang.IllegalAccessError: class test1.C 
(in module test1) cannot access class com.sun.jmx.remote.internal.ArrayQueue 
(in module java.management) because module java.management does not export 
com.sun.jmx.remote.internal to module test1

请注意,这与众所周知的非法反射访问警告不同,后者是关于使用反射访问私有字段或方法。这里我们静态(非反射)访问 public class(但来自非导出包)。