java 17 的 sealed 关键字用于显式声明类/接口仅允许被特定有限子类继承或实现,需用 permits 穷举直接子类,并要求子类声明 final、sealed 或 non-sealed;编译器强制执行,提升类型安全与模式匹配穷尽性。

Java 17 引入的 sealed 关键字,核心作用不是“控制演进边界”,而是**显式声明一个类/接口只允许被特定、有限的子类继承或实现**——它定义的是“谁可以继承我”,而非“未来能否修改”。所谓“绝对演进边界”是结果,而非设计目标;真正的控制力来自编译期强制约束和源码级契约。
sealed 类必须明确列出所有直接子类
声明 sealed 类时,必须用 permits 子句穷举所有允许的直接子类(不能是间接子类,也不能遗漏)。这些子类还必须显式声明自己如何继承该 sealed 类:用 final(禁止再继承)、sealed(可继续限制下级)或 non-sealed(开放继承)。
- 例如:
sealed interface Shape permits Circle, Rectangle, Triangle {} -
final class Circle implements Shape—— 终止演进 -
sealed class Rectangle implements Shape permits Square {}—— 允许且限制下级为Square -
non-sealed class Triangle implements Shape—— 开放后续任意扩展
编译器强制执行封闭性,任何绕过都会报错
如果你没在 permits 中列出某个类,却让它继承 sealed 类,javac 直接拒绝编译。同样,如果子类未声明 final、sealed 或 non-sealed,也会编译失败。
- 新增子类?必须修改 sealed 父类的
permits列表并重新编译整个模块 - 删除子类?需同步清理
permits并确保所有引用已处理 - 想让已有子类支持新行为?只能通过接口默认方法、组合或策略模式,不能靠新增继承分支
适合建模“有限、稳定、可枚举”的领域概念
sealed 特别适用于表达逻辑上完备且不易扩张的类型集合,比如 AST 节点、协议消息类型、状态机状态、几何图形分类等。它让 IDE 和静态分析工具能精准推导所有可能子类型,提升 pattern matching(switch 表达式)的穷尽性检查能力。
- 避免运行时
ClassCastException或漏处理分支 - 配合
switch (obj)自动提示未覆盖的子类型 - 相比枚举更灵活(支持不同字段、方法),比普通继承更安全(杜绝意外子类)
不是银弹:注意模块化与可见性约束
sealed 类及其 permits 列表中的类,必须在同一个模块(或同一包中,若未启用模块系统)。跨模块继承需导出包并声明 opens 或 exports,但 permits 列表仍只能写本模块内可见的类。
- 若子类在其他模块,sealed 类必须是
public且所在包已导出 - permits 中的类名必须可访问(不能是 package-private 类)
- 不建议将 sealed 类设为
private或protected—— 失去封装意义
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











