Java模块化环境下“找不到类”的本质是模块未正确声明requires、目标模块未exports对应包,或反射场景缺opens;关键在module-info.java精准配置三要素。

模块化环境下第三方库“找不到类”,本质是模块系统未正确导出或读取依赖,module-info.java 是唯一可控入口——关键不在“加依赖”,而在“精准声明依赖关系”。
明确模块对第三方库的访问需求类型
不是所有第三方 jar 都能直接用。JDK 9+ 要求:模块必须显式声明 requires 才能访问另一模块的 public 类;而类能否被访问,还取决于目标模块是否 exports 对应包。
- 若你用的是 已模块化 的库(如
com.google.gson、org.junit.jupiter.api),它自带module-info.class,只需在你的module-info.java中写requires 名字; - 若你用的是 传统 jar(无 module-info)(如老版本 log4j、commons-lang3),JVM 会将其自动封装为一个“自动模块(automatic module)”,模块名默认为 jar 文件名(去掉版本号和 .jar),例如
log4j-api-2.20.0.jar→ 模块名log4j.api,此时写requires log4j.api; - 若 jar 名含非法字符(如
slf4j-simple-1.7.36.jar),自动模块名会转为slf4j.simple(点号替代连字符),可用jdeps --list-deps your-app.jar或解压 jar 查看META-INF/MANIFEST.MF中的Automatic-Module-Name属性确认
解决“类可见但无法 new 实例”:检查 exports 和 opens
即使 requires 成功,若第三方库的类在某个包里,而该包未被导出(exports),你的模块仍看不到它。更隐蔽的是反射场景(如 Gson、Jackson 序列化):需运行时访问私有字段,这时光 exports 不够,得用 opens。
- 普通使用(如调用
new Gson()):确保你requires的模块已exports com.google.gson;(Gson 本身已做) - 反射使用(如
Gson.fromJson(json, MyBean.class)):Gson 需要读取MyBean的私有字段 → 你的模块必须opens mypackage;,否则抛InaccessibleObjectException - 若第三方库内部用反射访问你的类(如 Spring Boot 启动时扫描),你也需要
opens对应包,甚至opens到特定模块:opens mypackage to spring.core;
处理多版本冲突与服务加载(ServiceLoader)
当多个模块提供同一服务接口(如 java.sql.Driver),或你用 ServiceLoader.load(X.class) 加载第三方实现时,模块系统要求显式 uses 和 provides。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
立即学习“Java免费学习笔记(深入)”;
- 若你的代码调用
ServiceLoader.load(MyPluginInterface.class),必须在module-info.java添加:uses MyPluginInterface; - 若你实现该接口并打包为模块,需声明:
provides MyPluginInterface with com.example.MyPluginImpl; - 常见坑:HikariCP、PostgreSQL 驱动等需同时满足
requires+uses java.sql.Driver,否则DriverManager.getDrivers()返回空
快速验证与调试技巧
别靠猜——用 JDK 工具定位问题根源:
-
javac --module-path mods -d out src/module-info.java src/**/*.java编译时报错会明确指出“module not found”或“package not exported” -
java --module-path mods:lib --module myapp/mypackage.Main运行时若报NoClassDefFoundError,先检查是否漏requires;若报IllegalAccessError,重点查exports/opens -
jdeps --module-path lib --list-deps myapp.jar查看实际解析出的模块依赖图 - 用
--show-module-resolution参数启动 JVM,输出每个类从哪个模块加载,一目了然
不复杂但容易忽略:模块化不是给 classpath 换个名字,而是用 module-info.java 把“谁用谁”、“谁开谁”、“谁供谁”三件事写清楚。把第三方库当“人”来对待——想用它,先打招呼(requires);想进它家门,看它开门没(exports);想翻它抽屉,得它同意(opens)。做完这三步,90% 的“找不到类”就解决了。


















