Java 模块系统中 opens 和 exports 有什么区别
在 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 获得了对应开放范围。
Go runtime/trace 如何观察一次请求的调度过程
- 上一篇
- Go runtime/trace 如何观察一次请求的调度过程
- 下一篇
- Go errors.Is 自定义类型没匹配到是因为缺少什么
-
- 文章 · java教程 | 2小时前 | Java · websocket · java.net.http · java websocket httpclient 异步回调
- Java HttpClient WebSocket 连接如何处理异步回调
- 315浏览 收藏
-
- 文章 · java教程 | 3小时前 |
- Java Pattern 命名分组如何读取可选字段
- 209浏览 收藏
-
- 文章 · java教程 | 4小时前 | Java · nio · 文件系统 · WatchService · java 文件监听 Java NIO WatchService
- Java NIO WatchService 收不到子目录变化怎么办
- 338浏览 收藏
-
- 文章 · java教程 | 5小时前 | Java · 文件读取 · 资源管理 · nio · java Stream try-with-resources 文件句柄 Files.lines
- Java Files.lines 忘记关闭流为什么会占文件句柄
- 248浏览 收藏
-
- 文章 · java教程 | 6小时前 | 并发 · Java · 线程池 · java shutdown ExecutorService shutdownnow awaitTermination
- Java ExecutorService 关闭后如何等待任务完成
- 136浏览 收藏
-
- 文章 · java教程 | 8小时前 | Java · 并发编程 · CompletableFuture · java completablefuture allOf 异步结果
- Java CompletableFuture allOf 取不到子任务结果时怎样收集返回值
- 437浏览 收藏
-
- 文章 · java教程 | 11小时前 | Java · Stream · Collectors · 集合分组 · LinkedHashMap · Java Stream linkedhashmap Collectors.groupingBy 分组顺序 输入顺序
- Java Stream 分组后如何保留输入顺序
- 498浏览 收藏
-
- 文章 · java教程 | 12小时前 | 性能诊断 · Java Flight Recorder · 方法过滤 · MethodTrace · java JFR MethodTiming MethodTrace
- Java JFR 如何只记录指定方法的执行事件
- 139浏览 收藏
-
- 文章 · java教程 | 13小时前 | 并发 · Java · 上下文传递 · threadlocal StructuredTaskScope ScopedValue
- Java ScopedValue 如何替代跨线程上下文传递
- 364浏览 收藏
-
- 文章 · java教程 | 15小时前 |
- Java 虚拟线程访问同步块时如何识别 pinning
- 163浏览 收藏
-
- 文章 · java教程 | 1天前 | Java · 性能分析 · JFR · Flight Recorder JFR Java性能诊断
- Java JFR 事件采样如何降低诊断开销
- 129浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 108次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 23次使用
-
- OpenCompass
- OpenCompass是上海AI实验室推出的开源大模型评测平台,提供CompassKit、CompassHub和CompassRank三大核心组件,支持LLM及多模态模型的一站式标准化评估与排行榜查询。
- 41次使用
-
- AGI-Eval
- AGI-Eval是由上海交大等高校联合发布的大模型评测社区,提供公正透明的LLM能力榜单、多领域评测集及Data Studio数据服务,助力AI模型性能评估与NLP科研开发。
- 23次使用
-
- SuperCLUE
- SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
- 264次使用
-
- Goreflect反射原理示例详解
- 2022-12-22 174浏览
-
- 详解如何让Go语言中的反射加快
- 2023-02-24 246浏览
-
- Golang 中反射的应用实例详解
- 2022-12-31 353浏览
-
- Go语言的反射机制详解
- 2022-12-28 126浏览
-
- Go语言反射获取类型属性和方法示例
- 2023-01-08 395浏览

