判断jar路径归属的唯一标准是module-info.class是否存在:存在则必须放--module-path,否则只能放-cp;混用将导致split package错误或模块解析失败。

混合项目中同时用模块路径(--module-path)和类路径(-cp)不是不能做,而是必须守规矩——路径用途不能交叉,加载逻辑不能混淆。核心就一条:有 module-info.class 的 JAR 走模块路径,没有的只能走类路径。
怎么一眼判断该放哪条路径?
只看一个文件:module-info.class 是否存在。
- 运行
jar -tf your.jar | grep module-info.class,输出非空 → 必须进--module-path - 没输出 → 只能进
-cp;若硬塞进--module-path,JVM 会把它当作自动模块,包全导出、无封装,容易引发 split package 错误 - Spring Boot 3.x、Log4j2 2.20+、JUnit 5.9+ 等新版本大多含
module-info.class;而很多老工具包(如早期 Apache Commons 组件)仍是普通 JAR
启动参数怎么写才不出错?
两条路径要分开声明,不能混在同一个 -cp 或 --module-path 里。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 模块化 JAR 全部归到
--module-path(或-p),例如:--module-path mods/:lib/modular/ - 非模块化 JAR 全部归到
-cp,例如:-cp "lib/legacy/*.jar:classes/" - 如果模块代码里
requires了一个自动模块(即来自-cp的 JAR),JVM 会按 JAR 文件名推断模块名(如guava-31.1-jre.jar→ 模块名guava.31.1.jre),但你要在module-info.java里显式写上这个推断名 - 别漏加平台模块:用了
java.logging却没加--add-modules java.logging,尤其在自定义 JDK 镜像时常见报错
同名类或资源冲突怎么处理?
模块路径优先级永远高于类路径,这点很关键。
- 如果
com.example.Util同时出现在--module-path的 A.jar 和-cp的 B.jar 中,JVM 只加载 A.jar 里的,B.jar 的被静默忽略 - 资源加载(比如
Class.getResource())也遵循路径优先级:模块内调用默认从本模块及依赖模块找;-cp中的资源对模块代码不可见,除非通过未命名模块桥接(不推荐) - 避免反射越界:模块内用
Class.forName("x.y.Z")加载类时,若 Z 在-cp里,能加载成功但绕过所有模块约束;若 Z 在另一个模块里但没opens对应包,就会抛IllegalAccessError
构建和调试时要注意什么?
别靠猜,用命令和工具验证实际加载情况。
- 启动前跑
java --list-modules | grep xxx,确认目标模块是否已识别并加载 - Maven 项目执行
mvn dependency:tree -Dverbose,留意哪些依赖标注了modulescope或含module-info.class - IntelliJ 中启用 “Use --module-path for modules”,同时关闭 “Add dependencies to classpath” 类似选项,防止 IDE 自动混入
- 报错时先看本质:
Module not found是模块路径缺依赖;Unable to derive module descriptor是普通 JAR 被错当模块;NoClassDefFoundError往往是跨路径访问失败或封装限制
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










