Java 模块系统中 opens 和 exports 有什么区别
来源:17golang原创
时间:2026-09-12 23:39:49 496浏览 收藏
在 Java 模块系统里,exports 和 opens 都是在模块边界上“放行”一个包,但放行的对象不同:exports 解决其他可读模块对公开类型和成员的普通访问,opens 解决运行时反射,范围可以深入到非公开类型和成员。遇到依赖编译失败、IllegalAccessException 或框架绑定不到字段时,先按这个边界判断,通常就不会把两个关键字混用。
记忆方法:代码要直接调用公开 API,用exports;框架要在运行时反射私有字段或构造器,用opens。它们可以分别用to限定目标模块。
先把两个关键字放在同一张模块声明里
假设模块 orders.core 有一组稳定 API,还有只给序列化框架使用的模型包:
module orders.core {
// 对外提供可编译、可直接调用的公开 API
exports com.example.orders.api;
// 只允许指定框架对模型做运行时深反射
opens com.example.orders.model to framework.core;
}
exports 的对象是包的公开 API。目标模块必须能读到 orders.core,才能在编译或普通链接时使用导出的公开类型;它不会因此获得任意私有字段的反射写入能力。
opens 的对象是反射访问。打开后,指定目标模块可以检查包内类型及其成员,包括非公开成员,前提仍是反射 API 和运行时访问规则允许这样做。它不等于把包变成可在源码中直接导入的 API。

用访问场景判断应该写 exports 还是 opens
可以把问题拆成三个检查:
| 需求 | 应选 | 原因 |
|---|---|---|
| 客户端源码要声明并调用公开类 | exports | 这是模块间的普通类型访问 |
| 序列化、依赖注入或测试框架要读取私有字段 | opens | 这是运行时深反射 |
| 只想让某个模块使用内部公开类型 | exports 包 to 模块 | 把普通访问限定到指定读者 |
| 只想让某个框架反射模型 | opens 包 to 模块 | 把深反射权限限定到指定目标 |
一个常见误区是:看到框架提示“包未导出”就直接加 opens。如果框架只是调用包中的公开类型,应该先确认模块声明里是否有 exports,以及调用方是否声明了 requires。相反,若错误发生在 setAccessible、构造器绑定或字段注入阶段,问题更接近 opens。
用限定开放收窄模块边界
无条件的 exports com.example.orders.api; 会向所有能读取该模块的模块开放普通 API;限定形式则只给列出的模块:
module orders.core {
// 只有报告模块能在源码中使用这个公开包
exports com.example.orders.report to report.app;
// 只有序列化框架能对模型包做深反射
opens com.example.orders.model to framework.core;
}
如果想让模块中的所有包都对反射开放,可以声明 open module orders.core { ... },但它不是普通 API 的替代品:开放模块仍然需要用 exports 决定源码层面的包可见性。生产项目通常优先使用包级、目标明确的 opens,这样更容易发现哪个框架真正需要内部访问。
命令行补丁只解决启动边界
迁移旧框架时,可以暂时用启动参数补足模块描述符:
# 允许旧客户端访问未导出的公开类型;这里只是临时兼容补丁
java --add-exports orders.core/com.example.orders.internal=legacy.app \
--add-opens orders.core/com.example.orders.model=framework.core \
-m orders.app/com.example.orders.Main
--add-exports 对应普通公开类型访问,--add-opens 对应运行时深反射;目标若是类路径上的未命名模块,可写成 ALL-UNNAMED。两者都不是把权限永久写回 module-info.java,因此要把参数放进实际启动脚本并记录回收计划。若问题发生在编译阶段,javac 也有对应的 --add-exports 选项,但它不能替代运行时的反射开放。

最后可按“源码能否直接引用”“是否只需要公开成员”“是否要触达非公开成员”“目标是否应收窄”四个问题复查。源码依赖选 exports,深反射选 opens,能限定目标就不要无条件开放。
相关问题
opens 会自动让其他模块可以 import 这个包吗?
不会。opens 解决的是运行时反射边界,源码层面的普通访问仍要看 exports 和模块读取关系。
exports 能让框架访问 private 字段吗?
不能把它当作深反射授权。需要访问非公开成员时,应检查目标模块和包是否通过 opens 获得了对应开放范围。
-
174 收藏
-
246 收藏
-
353 收藏
-
126 收藏
-
395 收藏
-
315 收藏
-
209 收藏
-
338 收藏
-
248 收藏
-
136 收藏
-
437 收藏
-
128 收藏
-
文章 · java教程 | 11小时前 | Java · Stream · Collectors · 集合分组 · LinkedHashMap · Java Stream linkedhashmap Collectors.groupingBy 分组顺序 输入顺序498 收藏
-
文章 · java教程 | 13小时前 | 性能诊断 · Java Flight Recorder · 方法过滤 · MethodTrace · java JFR MethodTiming MethodTrace139 收藏
-
364 收藏
-
163 收藏
-
129 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习