防范密封类子类滥用继承的关键在于将“允许扩展”变为受控决策:需满足抽象基类设计、配套文档说明、模块显式授权三条件;阻断non-sealed类无限延伸;用模块边界锁定许可范围;以switch穷尽性检查作为自动防线。

防范密封类许可子类中滥用继承扩展点导致边界失控,关键在于把“允许扩展”变成一项受控决策,而非默认开放。它不是堵住所有门,而是把每扇门的钥匙、锁芯和开门记录都管起来。
只在明确意图处开放 non-sealed
non-sealed 不是“留个口子”,而是主动授予的扩展权。必须满足三个条件才可使用:
- 该子类本身设计为抽象基类,强制使用者实现核心契约(如抽象方法或模板方法)
- 有配套文档说明:为什么此处开放?扩展需遵守哪些约束?典型用例是什么?
- 所在模块已通过 module-info.java 显式声明 exports 或 opens,且仅对可信模块开放
限制非密封子类的传播深度
一旦某个 permitted 子类标记为 non-sealed,它的继承链就脱离了原始密封体系的管控。因此必须阻断无限向下延伸:
- 禁止 non-sealed 类再作为其他 sealed 类的 permitted 子类
- 要求所有直接子类必须声明为 final 或 sealed(不能再次 non-sealed)
- 在构建阶段加入检查规则:扫描 classpath 中所有 non-sealed 类,确认其父类是否属于你维护的密封体系;若发现多层 non-sealed 嵌套,构建失败
用模块边界加固许可范围
permits 列表只写类名不够,必须配合模块系统锁定物理边界:
- 密封父类所在的模块,不能 exports 其包给任意模块,只显式 requires 并 opens 给已知的实现模块
- 每个 permitted 子类必须位于被授权的模块内;跨模块实现会触发 JVM 类加载校验失败,而非仅编译报错
- CI 流水线中运行 jdeps --check 验证模块依赖图,确保无未授权模块间接引用密封类型
让 switch 成为自动防线
穷尽性检查不是锦上添花,而是架构边界的实时仪表盘:
- 所有对密封类型的模式匹配(switch 表达式、instanceof 模式)必须覆盖全部 permitted 子类
- 新增 permitted 子类时,编译器会强制所有已有 switch 更新;漏掉一个,整个项目无法编译
- 把核心业务逻辑(如状态流转、协议解析、错误分类)全部落在 switch 上,等于把“合法分支数”变成可量化的架构指标

















