模块导出是第一道硬边界,未在module-info.java中exports的包,即使含public类,其他模块也无法访问,反射亦不可穿透;访问修饰符仅在模块内生效,二者协同实现分层隔离。

多模块协同开发中,访问修饰符本身不能单独保障隔离安全,必须和模块系统(Java 9+ 的 module-info.java)配合使用,才能形成真正有效的访问隔离。
模块导出是第一道硬边界
即使某个类或方法被声明为 public,只要它所在的包没有在 module-info.java 中 exports,其他模块就完全无法访问——反射也无法穿透。这是 JVM 层面的强制约束,比访问修饰符更严格。
-
只导出 API 包:例如
exports com.example.api;,内部实现包如com.example.internal即使全是public类,外部模块也看不到、编译不通过 -
不导出的包默认私有:哪怕包内所有成员都是
public,未导出即不可见,彻底切断跨模块调用链 - 禁止跨模块访问 default 成员:default(包级私有)本就限于同包,而模块天然隔离包空间,进一步强化了该限制
访问修饰符在模块内继续承担职责
模块解决“谁可以跨模块调用”,访问修饰符解决“模块内谁可以访问什么”。两者分工明确:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- private:保护类内部状态,防止模块内其他类误用(如字段直接赋值、绕过校验逻辑)
- default:适合模块内工具类、辅助方法,仅限同包协作,避免污染模块公共接口面
- protected:用于模块内可被继承扩展的基类设计,子类可在同模块或子模块(若允许)中复用
-
public:仅用于
exports包中的对外契约,且应保持稳定;非导出包里的public是“伪公开”,实际不可达
规避常见组合风险
错误搭配会破坏隔离效果:
立即学习“Java免费学习笔记(深入)”;
-
导出包里暴露
public字段:违背封装原则,外部模块可随意修改内部状态 → 应改用private字段 +publicgetter/setter(或只提供 getter) -
用
protected替代模块导出控制:protected对不同包的子类仍可见,但模块未导出时,子类根本无法 import 到父类 → 此时protected失效,不如用default明确限定包内 -
忽略
requires的传递性:A 模块requires B并exports某个含 B 类型的接口,B 必须显式exports相关包,否则 A 的导出接口在外部模块中无法解析
文档与工具链同步验证
模块化访问控制需配套落地,否则容易“纸上隔离”:
-
Javadoc 自动过滤:运行
javadoc --modules时,仅生成exports包的文档,未导出内容不出现,避免误导开发者 - IDE 实时提示:IntelliJ 或 Eclipse 在跨模块引用时,对未导出包或非 public 成员直接标红,编译器拒绝通过
- 依赖图谱可视化:通过工具生成模块依赖关系图,确认无意外的强耦合(如某模块直接依赖另一模块的 internal 包)

















