Java 类路径与模块系统
classpath 如何定位类,JPMS 模块路径如何显式依赖与导出:两套模型的分工与迁移意识。
#type / concept
#status / growing
#tech / dev
#resource / java
[!info] 关联笔记
Java 类路径与模块系统
这个概念为什么出现
JVM 启动后必须知道“到哪里加载类”。经典答案是 classpath;Java 9+ 引入 JPMS 模块系统,用 module-info 声明依赖与导出。现实世界两者并存:应用可能仍以 classpath 为主,JDK 自身强烈模块化。
[!abstract] 一句话理解 classpath 是类查找的历史主路径;模块系统用显式依赖与 exports/opens 强化封装;排障时要分清类在哪条路径、被谁加载。
最小可观察示例
场景:理解运行时如何指定 classpath
# 编译到 out 目录
mkdir -p out
printf 'public class Hi{public static void main(String[] a){System.out.println("hi");}}' > Hi.java
javac -d out Hi.java
java -cp out Hi
期望输出:
hi
模块示例(概念):
// module-info.java
module shop.app {
requires java.base; // 隐式也可,示意
exports shop.api;
}
结合场景再看三个关注点
-cp指向目录/JAR 列表。- 包目录结构必须匹配。
- 模块化增加封装,反射默认可能需
opens。
核心概念与准确模型
1. classpath
- 冒号/分号分隔的目录与 JAR
- 先搜到的类优先(冲突隐患)
2. 模块路径
module-info.java:requires/exports/provides/uses- 更强封装与依赖显式化
3. 自动模块与未命名模块
- 兼容 classpath 世界的过渡机制(细节繁)
4. 与构建工具
- Maven/Gradle 生成 classpath/module path
边界情况与反直觉行为
- 同名类不同 JAR → 隐蔽错误。
- split package 在模块世界非法。
- 反射框架需打开模块。
常见误区
[!warning] 常见误区:认为模块系统可忽略 即便应用不写 module-info,也会与模块化 JDK/库交互(jlink、强封装)。
工程实践
- 依赖收敛,避免重复类。
- 可重现构建与锁定版本。
- 排障:
jdeps、-verbose:class。 - 新库评估是否支持 JPMS。
本节总结
- classpath 定位类;模块强化边界
- 冲突与封装是主战场
- 构建工具是日常入口
自测题
- 为什么依赖冲突会“同环境不同行为”?
- exports 的作用?
参考答案
- 不同机器/打包顺序导致 classpath 上胜出的类不同。
- 声明哪些包装其它模块可编译访问。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Project Jigsaw / JPMS | 项目 | 模块系统 |
| java command | 工具 | -cp / module path |