exports和opens不改变java访问修饰符作用范围,仅在模块系统层面控制包可见性与反射权限:exports放开public类的编译期可见性,opens解除目标模块对private等成员的反射限制。

exports 和 opens 都不改变 Java 原有的访问修饰符(public、protected、default、private)本身的作用范围,也不让 private 字段变成 public,更不会绕过编译期检查。它们是在模块系统层面叠加的一层访问通道控制,作用对象是包级可见性和反射运行时权限,与类内部的访问修饰符正交。
exports 不影响成员访问修饰符,只放开“包+public 类+public 成员”的可见链
声明 exports com.example.api; 后:
- 其他模块能 看到并编译通过这个包下的 public 类,比如
new com.example.api.UserService() - 但若该类里有个
protected方法或private字段,即使在导出包中,外部模块仍不能直接调用或访问——访问修饰符规则照常生效 - 如果类本身不是 public(比如 default 级),哪怕在 exports 包里,其他模块也无法引用它——模块系统不“提升”类的修饰符级别
opens 专为反射设计,但不改变字段/方法本身的修饰符语义
声明 opens com.example.model to com.example.app; 后:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 目标模块(如
com.example.app)可在运行时通过Field.setAccessible(true)访问该包内所有类的 private、protected 或 default 字段/方法 - 这仅解除 JVM 的反射封装限制(即避免
InaccessibleObjectException),不改变这些成员在源码中的修饰符;它们在编译期依然不可见、不可直接调用 - 注解读取、JSON 反序列化、JPA 实体构造等依赖反射的场景,必须靠
opens才能成功获取@Id、@Column等标注在 private 字段上的元数据
二者可共存,且各自职责明确,缺一不可
典型组合示例:
-
exports com.example.api;→ 让外部模块能正常使用你的 public 接口类 -
opens com.example.model to java.persistence;→ 让 JPA 框架能反射访问 model 包里的 private 字段及其注解 - 如果只写 exports,JPA 构造实体时会抛
IllegalAccessError - 如果只写 opens 而不 exports,外部模块连 model 类名都找不到(包不可见),反射也无从谈起
未命名模块(classpath)需特殊处理
当反射调用方来自传统 classpath(如 Spring Boot 2.x、JUnit 4 或直接 java -cp 启动):
- module-info.java 中不能写
to ALL-UNNAMED(语法非法) - 必须用 JVM 参数:
--add-opens com.example.model/java.base=ALL-UNNAMED - 或者改用
opens com.example.model to java.base;(因反射 API 在java.base中)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










