exports 控制模块间包的编译期可见性,仅允许其他模块引用已导出包中的 public 类型,不改变访问修饰符、不授予反射权限,需配合 requires 使用且模块名须严格匹配。

Java 9 模块系统中,exports 是控制包可见性的基础指令,它决定哪些包里的 public 类型 能被其他模块访问。但要注意:它本身不改变类或字段的访问修饰符,也不赋予反射权限——只解决“能不能在编译期引用”这一层问题。
基本写法:导出包给所有模块
在 module-info.java 中声明:
-
exports com.example.api;→ 允许任意模块(只要requires了你)使用该包下的public类和方法 - 必须确保包内类是
public的;包私有类(默认修饰符)或private成员,即使包被导出,也无法跨模块访问 - 子包不会自动导出,
exports com.example.api不包含com.example.api.v2,需单独写
精准控制:用 exports to 限定可信模块
避免无差别开放,改用定向导出:
-
exports com.example.secrets to com.example.reporter;→ 只有com.example.reporter模块能访问这个包 - 消费方模块必须同时在自己的
module-info.java中声明:requires com.example.lib; - 模块名要严格匹配(大小写、拼写),不能混淆为包名或 JAR 文件名
- 如果遗漏
requires或模块名错误,编译会报错:package not exported to this module
常见误区与关键细节
别把 exports 当成万能开关:
-
exports和opens完全不同:exports管正常调用,opens管反射(如 Jackson 序列化),两者不可替代 - 敏感字段安全靠的是
private或包私有修饰符,不是靠是否导出包。导出一个含private String token;的类,外部仍无法读写token - 非
public类(哪怕在已导出的包里)天然不可见,exports对它们无效 - 不要写
exports com.example.internal;—— 内部实现包应完全不导出,只供本模块使用
配套操作:让导出真正生效
光写 exports 不够,还需环境配合:
- 确保项目使用
--module-path启动,而非仅靠-cp;传统 JAR 若没模块描述符,会被视为 unnamed module,权限受限 - 若依赖第三方库未模块化,它会变成 automatic module,自动导出全部包,但失去精确控制能力
- 遇到
IllegalAccessError或ClassNotFoundException,优先检查:是否漏了requires?模块名是否拼错?包内类是否真为public?
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











