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;
}

结合场景再看三个关注点

  1. -cp 指向目录/JAR 列表
  2. 包目录结构必须匹配
  3. 模块化增加封装,反射默认可能需 opens

核心概念与准确模型

1. classpath

  • 冒号/分号分隔的目录与 JAR
  • 先搜到的类优先(冲突隐患)

2. 模块路径

  • module-info.javarequires/exports/provides/uses
  • 更强封装与依赖显式化

3. 自动模块与未命名模块

  • 兼容 classpath 世界的过渡机制(细节繁)

4. 与构建工具

  • Maven/Gradle 生成 classpath/module path

边界情况与反直觉行为

  1. 同名类不同 JAR → 隐蔽错误。
  2. split package 在模块世界非法。
  3. 反射框架需打开模块。

常见误区

[!warning] 常见误区:认为模块系统可忽略 即便应用不写 module-info,也会与模块化 JDK/库交互(jlink、强封装)。

工程实践

  1. 依赖收敛,避免重复类。
  2. 可重现构建与锁定版本。
  3. 排障:jdeps-verbose:class
  4. 新库评估是否支持 JPMS。

本节总结

  • classpath 定位类;模块强化边界
  • 冲突与封装是主战场
  • 构建工具是日常入口

自测题

  1. 为什么依赖冲突会“同环境不同行为”?
  2. exports 的作用?
参考答案
  1. 不同机器/打包顺序导致 classpath 上胜出的类不同。
  2. 声明哪些包装其它模块可编译访问。

延伸阅读与资料来源

资料类型支撑内容
Project Jigsaw / JPMS项目模块系统
java command工具-cp / module path
创建于 2026/7/15 更新于 2026/7/15