Java 17引入的密封接口(JEP 409)通过sealed关键字和permits子句限制实现类,要求每个许可类型必须声明final、sealed或non-sealed修饰符,编译器强制校验以增强类型安全与可维护性。

Java 密封接口(Sealed Interface)是 Java 17 引入的特性(JEP 409),用于显式限制哪些类或接口可以实现(或继承)某个接口,从而增强 API 的可维护性和类型安全性。
密封接口的定义方式
定义密封接口需使用 sealed 关键字,并通过 permits 子句列出所有被允许实现该接口的类或接口名。这些实现类/接口必须与密封接口在同一个编译单元(即同一模块、同一包,且通常建议在同一源文件或相邻文件中)。
示例:
public sealed interface Shape permits Circle, Rectangle, Triangle {}
注意:
- permits 列表中的类型必须是具体类(如 Circle)或接口(如 CurvedShape),不能是抽象类(除非它也声明为 sealed 或 non-sealed);
- 密封接口本身不能被任意类实现,未在 permits 中声明的类型编译时会报错;
- 所有 permits 列出的类型,必须显式声明其对密封接口的“继承关系”并指明自身是否继续密封。
实现类的三种许可修饰符
每个被允许实现密封接口的类型,必须使用以下三者之一作为修饰符:
立即学习“Java免费学习笔记(深入)”;
- final:不可再被继承,彻底封闭该分支。适合无扩展需求的实体类。
-
sealed:自身也是密封的,可进一步用
permits限制其子类型。适用于需要分层建模的场景(如Shape → CurvedShape → Circle)。 - non-sealed:开放该分支,允许任意类继承或实现。适用于需保留扩展灵活性的中间类型。
示例:
public final class Circle implements Shape { /* ... */ }
public sealed interface CurvedShape extends Shape permits Circle, Ellipse {}
public non-sealed class Ellipse implements CurvedShape { /* ... */ }
编译器强制执行的约束
Java 编译器在编译阶段严格校验密封关系,违反规则将直接报错:
- 未在
permits中声明却尝试实现密封接口 → 编译失败; -
permits列出的类型未声明final、sealed或non-sealed→ 编译失败; -
sealed实现类未提供自己的permits列表(当它本身也声明为sealed时)→ 编译失败; - 跨模块使用密封接口时,需在
module-info.java中显式导出并开启密封类型访问(使用opens或exports配合to)。
典型使用场景
密封接口特别适用于建模有限、明确且稳定的类型集合:
- 领域模型中的枚举式结构(如支付方式:
PayPal、CreditCard、CryptoWallet); - AST(抽象语法树)节点类型,确保所有节点类型可穷举、可模式匹配(配合
switch表达式); - 协议消息类型(如 RPC 响应:
Success、ValidationError、Timeout),便于静态分析和序列化策略统一; - 替代传统
enum无法携带行为的局限,同时比开放接口更安全。








