Java 9 – “模块”和“JAR”文件有什么区别?

我正在从Java9的What’s New中学习Java 9,讨论的热门话题之一是模块化JDK

我有些疑惑:

  1. JAR文件是模块吗?
  2. 模块与JAR文件有何不同?

模块 :Java 9中引入的一种新语言特性(类似于类,接口,包等),由一组包组成,类似于包由一组类型组成。

JAR :一种归档文件格式,它捆绑代码和资源,可以由JVM加载。

更具体地说,模块定义如下 :

为了以一种既可供开发人员使用又可由现有工具链支持的方式提供可靠的配置和强大的封装,我们将模块视为一种基本的新型Java程序组件。 模块是一个命名的,自描述的代码和数据集合。 它的代码被组织为一组包含类型的包,即Java类和接口; 其数据包括资源和其他类型的静态信息。

模块的自描述在其模块声明中表示, 模块声明是Java编程语言的新结构。

按照惯例,模块声明被编译到名为module-info.class的文件中,类似地放在类文件输出目录中。

可以将模块编译为Jar文件,在这种情况下,Jar文件标记为模块化Jar文件

现有工具已经可以创建,操作和使用JAR文件,因此为了便于采用和迁移,我们定义了模块化JAR文件 。 模块化JAR文件在所有可能的方式都类似于普通的JAR文件,除了它在根目录中还包含module-info.class文件。

模块和JAR之间的一些其他差异:

  1. 模块可以要求其他模块,以允许需求模块访问依赖类。 Jar没有这样的依赖概念。

  2. 模块可以决定将哪些类和接口导出到需要它的其他模块。 Jar没有这样的封装机制。

  3. 模块可以编译成模块化的Jar文件,但是一些模块(例如JDK模块)被编译成另一种称为JMOD的格式。

  4. 可以更改JAR的名称。 只要JVM类加载器在类路径上找到所需的类(可以由单个JAR,多个JAR或目录或JAR之间的混合组成),JAR文件的名称就可以是任何名称。 但是,模块的名称可以在其他模块的声明中显式引用,并且这样的名称定义它并且不能自由更改。

JAR文件是模块吗? 模块与JAR文件有何不同?

不, Java Archive不是模块

仅举一个例子,虽然同一个包的类可以分布在JAR中 ,但现在无法从多个模块中读取相同的包。

JAR是一种文件格式,使您可以将多个文件捆绑到一个归档文件中。 通常,这包含与applet和应用程序关联的类文件和辅助资源。

另一方面(我试着在这里描述〜> java-module )

模块是一个命名的,自描述的代码和数据集合。 它的代码被组织为一包含类型的包 ,即Java类和接口; 其数据包括资源和其他类型的静态信息。

这也包含在module-info.java的帮助下指定的模块声明。

每个模块定义都是

  • 模块工件 ,即模块化JAR文件或包含已编译模块定义的JMOD文件 ,否则

  • 一个分解模块目录 ,按照惯例,其名称是模块的名称,其内容是与包层次结构对应的“展开”目录树。

正如模块系统所介绍的,模块化图像由模块而不是JAR文件组成。 对于模块化WAR文件 ,动态配置也可以预见模块化。


但是为了便于采用模块化JAR文件,在JDK9中引入了这样的模块,例如,对于一个由module-info.java组成的模块,

 module com.foo.bar { } 

和其他java类一样

 com/foo/bar/alpha/AlphaFactory.java com/foo/bar/alpha/Alpha.java 

现有工具已经可以创建,操作和使用JAR文件。 模块化JAR文件在所有可能的方式都类似于普通的JAR文件,除了它在根目录中还包含module-info.class文件。 上述com.foo.bar module模块化JAR文件,例如,可能包含以下内容:

 META-INF/ META-INF/MANIFEST.MF module-info.class com/foo/bar/alpha/AlphaFactory.class com/foo/bar/alpha/Alpha.class ... 

模块化JAR文件可以用作模块,在这种情况下,其module-info.class文件用于包含模块的声明。 或者,它可以放在普通的类路径上,在这种情况下,它的module-info.class文件将被忽略。

严格来说, 模块是运行时概念。 正如其他人引用了“模块状态”系统 :

模块是一个命名的,自描述的代码和数据集合。 它的代码被组织为一组包含类型的包,即Java类和接口; 其数据包括资源和其他类型的静态信息。

这与JAR非常相似,但……

  1. JAR在运行时没有有意义的表示
  2. JAR不是“自描述​​”,在这种情况下,它们意味着它们没有JVM关心的名称,无法表达依赖关系或定义适当的API

这就留下了问题,模块来自哪里? 有多种方式,但开发人员最突出的方法是模块化JAR。 模块化JAR就像普通的JAR,但它包含一个模块描述符 ,一个从module-info.java编译的文件module-info.class module-info.java 。 该文件定义了模块的名称,依赖关系和API 。

因此,JAR和模块之间存在强大的联系:JAR是模块系统从中创建模块的容器,并且(目前)每个JAR只能包含一个模块。 值得注意的是,即使在Java 9 JAR上也不必是模块化的 – 普通的JAR完全没问题。