java模块化系统(jpms)通过显式声明依赖、强制封装和启动强校验,彻底取代类路径机制,杜绝隐式调用、版本冲突与类加载异常。

Java 模块化系统(JPMS)不是靠“绕开”或“缓解”类路径地狱,而是从机制层面重写依赖规则——它用显式声明、强制封装、启动校验三把锁,把“隐式、扁平、侥幸”的类路径逻辑彻底替换掉。
模块必须声明依赖,不声明=不可见
传统类路径下,只要 JAR 在 -cp 里,所有 public 类自动对其他所有 JAR 可见,极易形成隐式调用链。模块系统强制每个模块在 module-info.java 中写明 requires,比如:
-
requires java.sql;→ 只能访问java.sql模块导出的包 -
requires com.example.logging;→ 若该模块未导出其内部工具类包,即使类存在也无法访问 - 没写
requires的模块,哪怕物理上存在,运行时直接抛NoSuchModuleException
模块名唯一 + 启动强解析,杜绝版本混杂
类路径用“先来后到”覆盖同名类(如 log4j-2.15.jar 和 log4j-2.17.jar 共存),而模块路径要求:
- 同名模块(如两个都声明
module org.apache.logging.log4j)无法同时加载,JVM 启动即报ResolutionException - 自动模块(无
module-info.class的 JAR 放入 --module-path)也按文件名推断模块名(如slf4j-api-2.0.9.jar→ 模块名slf4j.api),同样受唯一性约束 - 想共存不同版本?必须重命名模块(
module org.apache.logging.log4j.v2_17)或使用多版本 JAR,不能靠“赌顺序”
封装默认关闭,导出即授权
类路径时代,“public 就等于全世界可用”。模块系统反转逻辑:
- 所有包默认私有,外部模块完全不可见
- 只有显式
exports com.example.api;的包,才对外暴露 - 若需反射访问(如框架需操作内部类),必须额外
opens com.example.internal; - 这意味着:即使两个 JAR 都含
org.apache.commons.lang3.StringUtils,只要它们不在同一模块、且未被共同依赖,就不会发生类加载冲突
构建与运行双阶段验证,问题前移
类路径问题常在运行时爆发(NoClassDefFoundError、IllegalAccessError)。模块系统把校验提前:
- 编译期:
javac --module-path检查requires是否可解析 - 启动时:JVM 解析整个模块图,确认所有依赖闭环、无循环、无缺失
- 工具辅助:
jdeps --list-deps查实际依赖链,jlink --list-modules看最终镜像组成,冗余项一目了然
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











