Java 9
Java 9 引入了模块系统(Project Jigsaw),这是 Java 语言自诞生以来的一次重大变革。模块系统旨在更好地组织代码、提高可维护性、封装性以及安全性,尤其是在大型项目中尤为有用。
1. 模块的基本概念
在 Java 9 中,模块是一个自包含的代码单元,包含包、类和资源。模块可以显式声明其依赖关系和可见性,这样可以更好地控制访问权限和减少类路径的复杂性。
模块声明文件 (module-info.java): 每个模块都需要一个 module-info.java 文件,用于定义模块的名称、依赖和暴露的包。
2. 模块的声明
module-info.java 文件是模块的核心,它定义了模块的基本结构和依赖。
// module-info.java
module com.example.myapp { // 定义模块名称
requires java.base; // 声明依赖的模块,java.base 是隐式依赖的
exports com.example.myapp.services; // 声明要暴露的包
}
3. 模块的依赖
模块可以通过 requires 关键字声明其依赖的其他模块。这使得模块之间的依赖关系清晰可见。
// module-info.java
module com.example.mylibrary { // 定义模块名称
requires com.example.myapp; // 声明对其他模块的依赖
exports com.example.mylibrary.utils; // 暴露该模块的包
}
4. 模块的导出
通过 exports 关键字,模块可以选择性地暴露其中的包。未暴露的包对外部模块是不可见的,这增强了封装性。
// module-info.java
module com.example.myapp {
exports com.example.myapp.services; // 只暴露 services 包,其它包对外不可见
exports com.example.myapp.utils; // 另外暴露 utils 包
}
5. 模块的使用
在使用模块的代码中,需要在 module-info.java 中声明对其他模块的依赖。
// com/example/myapp/services/MyService.java
package com.example.myapp.services;
public class MyService {
public String service() {
return "Service is running";
}
}
// com/example/mylibrary/MainApp.java
package com.example.mylibrary;
import com.example.myapp.services.MyService;
public class MainApp {
public static void main(String[] args) {
MyService service = new MyService(); // 创建服务实例
System.out.println(service.service()); // 调用服务方法并打印结果
}
}
6. 编译和运行模块化应用
编译模块化应用程序与传统 Java 项目略有不同。
# 编译模块
javac -d out --module-source-path src $(find src -name "*.java") # 编译源文件,并指定模块化源路径
# 运行模块
java --module-path out -m com.example.mylibrary/com.example.mylibrary.MainApp # 指定模块路径并运行主类
7. 服务加载机制
Java 9 模块系统支持服务加载机制,可以定义接口,并由模块提供实现。
// module-info.java (服务定义)
module com.example.myapp {
exports com.example.myapp.services;
uses com.example.myapp.services.MyService; // 声明使用某个服务接口
}
// module-info.java (服务实现)
module com.example.myserviceimpl {
requires com.example.myapp;
provides com.example.myapp.services.MyService with com.example.myserviceimpl.MyServiceImpl; // 提供服务的实现类
}
// 服务接口
package com.example.myapp.services;
public interface MyService {
String service();
}
// 服务实现
package com.example.myserviceimpl;
import com.example.myapp.services.MyService;
public class MyServiceImpl implements MyService {
@Override
public String service() {
return "Service Implementation is running";
}
}
8. 模块的限制和强制访问
在 Java 9 中,使用 requires transitive 可以确保依赖的模块也可以被其他依赖该模块的模块访问。
// module-info.java
module com.example.mylibrary {
requires transitive com.example.myapp; // 使得依赖此模块的其他模块也可以访问 com.example.myapp
exports com.example.mylibrary.utils;
}
9. 反射和模块
模块系统对反射有严格的访问控制。如果要通过反射访问模块的私有成员,需要在 module-info.java 中使用 opens 关键字。
// module-info.java
module com.example.myapp {
opens com.example.myapp.services; // 允许反射访问 services 包的私有成员
}
总结
Java 9 的模块系统为 Java 提供了强大的模块化支持,极大地改善了大型项目的代码组织和管理能力。通过模块系统,开发者可以清晰地定义模块的依赖关系、导出接口和封装实现,同时增强了代码的安全性和可维护性。