Java访问权限与JPMS分层协同:包级权限(如default)在编译期保障模块内高内聚,模块系统通过exports/requires在运行时控制跨模块低耦合,二者语义一致方能实现真正模块化。

Java 的访问权限机制与模块系统(JPMS)不是简单叠加,而是分层协同:包级权限在编译期划定协作边界,模块系统在运行时强化隔离策略。两者配合得当,才能真正实现“高内聚、低耦合”的模块化设计。
包级权限是模块化的基础支撑
默认(package-private)修饰符天然适配模块内协作——它让同包类自由交互,同时阻止跨包误用。这种约束不依赖运行时检查,编译失败即暴露越界调用,是模块内部稳定性的第一道防线。
- 比如
com.example.order.impl包内多个default工具类可直接调用彼此,但外部包哪怕在同一模块中也无法访问 - 若把关键实现类设为
public,就等于提前向所有模块开放接口,违背封装初衷 - 包名语义化(如
.api、.spi、.impl)配合默认权限,能自然映射出模块的职责分层
模块声明(module-info.java)控制跨模块可见性
即使一个类是 public,也必须通过 exports 显式导出所在包,其他模块才能访问其中的 public 类型。模块系统不关心类内部用的是 private 还是 protected,只管控“哪些包对外可见”。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
exports com.example.order.api;→ 允许其他模块使用该包下的public接口类 -
exports com.example.order.spi to com.example.payment;→ 仅允许指定模块访问 SPI 包 - 未导出的包,哪怕全是
public类,其他模块连编译都通不过
权限修饰符与模块导出需保持语义一致
模块导出是“对外承诺”,而类内修饰符是“对内约束”。二者错位会导致设计失真:
立即学习“Java免费学习笔记(深入)”;
- 导出了
com.example.order.api,但该包里混入了default的内部工具方法 → 实际不可用,徒增理解成本 - 某个
public类依赖default的构造器参数,却导出了这个类 → 外部无法实例化,违反契约 - 推荐做法:API 包只放
public接口和public抽象类;SPI 包用public接口 +default回调钩子;实现包尽量用default,必要时才提升为public
常见脱节场景与规避方式
没有模块系统时,默认权限靠类路径隐式生效;启用 JPMS 后,若忽略 module-info.java 配置,包级权限仍有效,但跨模块调用可能因缺失 requires 或 exports 而失败。
- 两个模块各自定义
com.example.common包 → 默认权限成员仍可互相访问(类路径合并导致),这不是模块系统失效,而是包命名冲突,应避免通用包名 - 模块 A 导出了包,但模块 B 没写
requires A;→ 编译报错“package not visible”,需补全依赖声明 - 使用
open或opens是反射特例,不应作为常规访问手段;它绕过封装,只用于测试或框架集成等有限场景

















