Java 模块是 Java 9 引入的一项新功能,它是一种组织和打包 Java 代码的方式。模块化使得开发人员可以将代码划分为独立的模块,并明确定义它们之间的依赖关系。
每个 Java 模块都包含一个模块描述文件module-info.java
,其中定义了模块的名称、依赖关系和导出的包。模块描述文件还可以指定模块的访问级别,以控制其他模块对其内部的可见性。
使用 Java 模块可以带来一些好处,包括更好的代码组织和可维护性,更好的封装性和可重用性,以及更好的性能和安全性。 要使用 Java 模块,您需要使用 Java 9 或更高版本的 JDK,并按照模块化的约定组织您的代码。您可以使用命令行工具(如javac
和java
)编译和运行模块化的应用程序,也可以使用构建工具(如Maven
或Gradle
)来管理模块化的项目。
编写模块
要编写一个 Java 模块,您需要按照以下步骤进行操作: 创建模块描述文件:在您的项目中创建一个名为module-info.java
的文件。该文件应该位于模块的根目录下。在这个文件中,您需要定义模块的名称、依赖关系和导出的包。以下是一个示例模块描述文件的基本结构:
module your.module.name {
requires module1;
requires module2;
exports com.example.package1;
exports com.example.package2;
}
- 组织代码结构:按照模块化的约定组织您的代码。您可以将相关的类和资源放在同一个包或子包中,并根据需要将其导出或隐藏。
- 编写代码:在适当的包中编写您的 Java 类和其他代码。确保按照模块描述文件中指定的导出规则来访问和使用其他模块的类。
- 编译模块:使用 Java 编译器(javac)编译您的模块。您可以使用以下命令来编译模块:
javac -d <output_directory> --module-source-path <source_directory> <module_descriptor>
其中,<output_directory>
是指定编译输出目录的路径,<source_directory>
是指定源代码目录的路径,<module_descriptor>
是模块描述文件的路径。
- 运行模块:使用 Java 虚拟机(java)来运行您的模块。您可以使用以下命令来运行模块:
java --module-path <module_path> --module <module_name>/<main_class>
其中,<module_path>
是指定模块路径的路径,<module_name>
是您的模块的名称,<main_class>
是包含main
方法的主类。
这些是编写Java模块的基本步骤。请注意,具体的实现可能会因您的项目和需求而有所不同。
打包jre
要打包 Java 运行时环境(JRE),您可以使用 Java 的模块系统和jlink
工具。下面是打包JRE
的一般步骤:
- 创建模块描述文件:首先,您需要为您的应用程序创建一个模块描述文件
module-info.java
。模块描述文件指定了模块的名称、依赖关系和导出的包等信息。 - 组织代码结构:将您的应用程序代码组织成模块。每个模块都有自己的代码和资源文件。
- 编写代码:编写您的应用程序代码,并确保模块之间的依赖关系正确。
- 编译模块:使用
javac
命令编译您的模块。例如,如果您的模块名为com.example.app
,您可以使用以下命令编译模块:
javac --module-source-path src -d out --module com.example.app
这将在out
目录中生成编译后的模块。 5. 创建JRE:使用jlink工
具创建 JRE。jlink
工具将根据您的应用程序的需要,从 Java 安装目录中提取所需的模块,并将它们打包到一个自定义的JRE中。
jlink --module-path <module-path> --add-modules <module-name> --output <output-path>
其中,<module-path>
是包含您的模块的路径,<module-name>
是您的应用程序的模块名,<output-path>
是JRE输出的路径。 6. 运行应用程序:使用JRE中的java
命令运行您的应用程序。
模块访问权限
在 Java 模块系统中,模块之间的访问权限是通过模块描述文件module-info.java
中的exports
和requires
语句来定义的。
- exports语句:exports 语句用于指定模块中可以被其他模块访问的包。您可以在模块描述文件中使用多个
exports
语句来指定多个包的访问权限。例如:
module com.example.moduleA {
exports com.example.packageA;
}
在上面的示例中,com.example.packageA
包中的类可以被其他模块访问。
- requires语句:
requires
句用于指定模块所依赖的其他模块。通过requires
语句,您可以确保在编译和运行时,所需的依赖模块已经存在。例如:
module com.example.moduleA {
requires com.example.moduleB;
}
在上面的示例中,com.example.moduleA
模块依赖于com.example.moduleB
模块。
- opens语句:
opens
语句用于指定模块中可以被其他模块反射访问的包。反射访问是指在运行时通过反射机制访问包中的类和成员。例如:
module com.example.moduleA {
opens com.example.packageA;
}
在上面的示例中,com.example.packageA
包中的类可以被其他模块通过反射访问。
模块之间的访问权限是双向的。如果模块A导出了一个包,模块B可以访问该包。但是,如果模块A没有导出该包,模块B将无法访问该包。
此外,还可以使用requires transitive
语句来传递模块的依赖关系。这意味着如果模块A依赖于模块B,并且模块B又依赖于模块C,那么模块A将自动依赖于模块C,而无需显式声明。 这些是 Java 模块系统中用于控制模块访问权限的基本语句。通过合理地使用这些语句,您可以确保模块之间的访问关系符合您的应用程序的需求。