非模块化项目可使用命名模块,但须将依赖jar放模块路径并用--module-path启动;jvm自动使其被未命名模块可读,但不可访问未导出包,且requires static/transitive无效。

非模块化项目(即没有 module-info.java 的传统 classpath 项目)可以使用命名模块(named module),但需满足两个前提:JVM 启动时必须用 --module-path 而非 -cp,且所有依赖的命名模块必须放在模块路径上——否则它们会被降级为自动模块或根本不可见。
确保模块路径正确设置
即使主项目是非模块化的,只要它依赖某个已模块化的 JAR(如 slf4j-api-2.0.13.jar 或 gson-2.10.1.jar),就必须把该 JAR 放进模块路径,而不是类路径。否则 JVM 无法识别其 module-info.class,也无法执行模块解析。
- 命令行运行时,用
java --module-path lib/ --class-path . MyApp,其中lib/下放的是命名模块 JAR - IDEA 中需手动修改 Run Configuration:在 VM options 里加
--module-path lib/,并**清空 Classpath 设置**(或设为“Use classpath of module”并选空模块) - Maven 用户推荐用
exec:java插件,它默认将compile输出和dependency:copy-dependencies结果统一纳入模块路径
命名模块会自动变成“可读模块”
在非模块化项目中,JVM 会把所有位于模块路径上的命名模块自动加入“未命名模块”的可读集合(readability graph)。这意味着你可以直接 new 它们的公开类、调用其 public 方法,无需 requires 声明——这是 JPMS 对兼容性的关键设计。
- 例如:
gson-2.10.1.jar含module-info.class声明module com.google.gson,你在普通 Main 类里写new Gson()完全合法 - 但注意:你不能访问它未导出(
exports)的包,比如com.google.gson.internal依然受封装限制 - 若某命名模块声明了
requires static或requires transitive,这些依赖对非模块化项目无效,只影响其他命名模块
避免常见陷阱
混合使用模块路径与类路径极易引发冲突。尤其当同一个库既出现在 --module-path 又出现在 -cp 时,JVM 会报错或静默忽略其中一个。
- 不要把命名模块 JAR 同时放进
--module-path和-cp;非模块化项目应只用前者承载模块化依赖 - 第三方库若未模块化(无
module-info.class),它会成为自动模块——名称由 JAR 文件名推断(如commons-lang3-3.12.0.jar→ 自动模块名org.apache.commons.lang3),此时仍可requires org.apache.commons.lang3,但仅限于其他命名模块中;非模块化项目中它只是普通 classpath 行为,不受模块规则约束 - 检查模块是否真被加载:运行时加
--show-module-resolution参数,观察输出中是否有find module com.google.gson这类日志
何时需要转为真正模块化项目
如果你发现以下情况,说明非模块化方式已到边界,建议补上 module-info.java:
- 要控制反射访问(如 Spring、Hibernate 需打开
opens包) - 需精确传递依赖(
requires transitive)给下游使用者 - 想利用 jlink 构建最小化运行镜像
- 遇到
IllegalAccessError且确认是因未导出内部包导致
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











