javac编译模块化项目必须显式指定--module-source-path:因模块路径与源码路径分离,需用该参数指向含所有模块子目录的父目录,否则报“module not found”;且运行时必须用--module-path和-m启动,不可用-cp。

javac编译模块化项目必须显式指定--module-source-path
Java 9+ 的模块化项目不能像传统项目那样直接用 javac *.java 编译。javac 默认不扫描模块结构,会报错 error: module not found: xxx 或直接忽略 module-info.java。核心原因是:模块路径(module path)和源码路径(source path)是分离的,且 javac 需要提前知道所有模块的布局才能做跨模块符号解析。
正确做法是把整个模块目录树作为源码根传入,并启用模块感知模式:
- 确保每个模块是一个独立目录,内含
module-info.java和对应包结构(如com.example.util) - 使用
--module-source-path指向包含所有模块子目录的父目录,例如:javac --module-source-path src -d out src/com.example.main/module-info.java src/com.example.main/com/example/main/Main.java - 若依赖外部模块(如自定义的
com.example.lib),它也必须在同一个--module-source-path下,或通过--module-path提供已编译的.jar - 不要混用
-sourcepath和--module-source-path,后者会覆盖前者,且不兼容
运行时必须用--module-path和--module,不能只靠-cp
即使编译成功,用 java -cp out Main 运行模块化项目大概率失败,报错 Error: Could not find or load main class Main 或 No module descriptor found。这是因为 JVM 启动时若未启用模块系统,就不会加载 module-info.class,所有类都落入“未命名模块”,而模块化代码中声明的 requires 无法满足。
正确启动方式强制分两步:
- 用
--module-path(缩写-p)提供所有模块的输出目录或 JAR 路径,例如:java --module-path out -m com.example.main/com.example.main.Main -
-m参数格式为<module-name>/<main-class-fullname></main-class-fullname></module-name>,中间是斜杠,不是点;模块名来自module-info.java中的module xxx { },不是目录名 - 如果主模块依赖其他模块,那些模块必须全部出现在
--module-path中,否则启动时报Module xxx not found - 不能同时用
-cp和--module-path启动模块化主类——JVM 会忽略-cp,除非你明确用--add-modules把类路径内容提升为命名模块(极少需要)
OpenJDK 8 不支持模块化,别试module-info.java
如果你在 OpenJDK 8 环境下写了 module-info.java,javac 会直接报错 error: invalid flag: module-info.java。这不是配置问题,是语言层面缺失:模块系统(Jigsaw)从 Java 9 / OpenJDK 9 才正式引入。OpenJDK 8 的 javac 解析器根本不认识 module 关键字。
验证方法很简单:
- 运行
java -version,输出里不含9、11、17、21等数字,基本可判定不支持 - 尝试编译任意含
module xxx { }的文件,错误信息里出现class, interface, enum, or record expected就是典型信号 - 想用模块化,最低要求是 OpenJDK 9,但生产推荐 OpenJDK 11+ LTS 版本,因 OpenJDK 9/10 已 EOL,无安全更新
IDE 和构建工具默认不启用模块模式,要手动开
IntelliJ IDEA、Eclipse 或 Maven 默认按传统 classpath 模式处理项目,即使你加了 module-info.java,它们也不会自动用 --module-source-path 编译,也不会用 --module-path 运行。结果就是 IDE 里能“跑起来”,但命令行执行失败,或者打包后 JAR 无法运行。
关键动作必须手动补全:
- IntelliJ:File → Project Structure → Project → Project SDK 必须设为 JDK 11+;Modules → Sources → 标记
src为 “Sources” 后,还要勾选 “Use module compile output path” 并指定每个模块的 output path - Maven:需启用
maven-compiler-plugin的release或source/target设为 9+,并添加<compilerargs></compilerargs>传入--module-source-path;更稳妥是用maven-jar-plugin生成模块化 JAR,并在MANIFEST.MF中写入Automatic-Module-Name或直接用jlink - Gradle:
java { modularity.inferModulePath = true }是必要开关,否则compileJava任务仍走旧流程 - 最容易被忽略的是:IDE 的 Run Configuration 里,“Use classpath of module” 不等于模块化运行——必须切换成 “Run with JLink” 或手动在 VM options 里加
--module-path和--module
module-info.java,整个编译、链接、运行链路就彻底切换到模块语义,任何环节漏掉 --module-xxx 参数,都会退化成不可预测的行为。











