sealed接口的核心目标是构建可穷举、可验证、不可随意扩展的类型边界,需显式声明permits列表并配合final/sealed/non-sealed修饰实现类,且所有实现者须在同一模块中。

用 sealed 修饰接口,核心目标是构建一个**可穷举、可验证、不可随意扩展**的类型边界。它不是简单加个关键字,而是通过语法约束 + 编译检查,把“谁可以实现我”这件事提前锁定在代码里。
密封接口必须显式声明允许的实现者
接口本身要带 sealed,并紧跟 permits 列出所有合法实现类或子接口。这些类型必须与接口在同一个模块中(默认模块也算),且不能遗漏、不能多写、不能用通配符。
public sealed interface PaymentMethod permits CreditCard, PayPal, CryptoWallet { }- 如果漏掉
CryptoWallet,编译器会报错:“CryptoWalletis not allowed to implement sealed interface” - 如果写了不存在的类名,比如
Alipay,同样编译失败
每个实现者必须明确声明继承策略
被 permits 列出的每一个类或接口,都必须用 final、sealed 或 non-sealed 显式修饰,不能省略,也不能用其他修饰符替代。
-
final class CreditCard implements PaymentMethod→ 彻底封闭,不能再有子类 -
sealed class PayPal implements PaymentMethod permits PayPalExpress, PayPalStandard→ 可继续分层,但下一层也必须受控 -
non-sealed class CryptoWallet implements PaymentMethod→ 开放继承,任何类都能继承它,但仅限这一条出口
整个体系需保持逻辑完整性与模块可见性
密封不是孤立的语法糖,它依赖模块系统和设计意图协同生效。
- 所有
permits类型必须能被接口“看到”——即在同一模块,或通过requires正确导出 - 不允许跨模块隐式实现:即使另一个模块定义了同名类,只要没出现在
permits列表中,就无法实现该接口 - IDE 和编译器能据此做穷举检查,例如
switch表达式匹配所有实现时,不写default也不会警告,因为已知分支完全覆盖
典型适用场景:领域模型、协议枚举、状态机
当业务概念天然有限且稳定时,密封接口比 enum 更灵活,又比普通接口更安全。
- 订单状态:
sealed interface OrderStatus permits Pending, Confirmed, Shipped, Cancelled - 消息类型:
sealed interface Message permits TextMessage, ImageMessage, VoiceMessage - 不适用于需要第三方插件动态扩展的场景——那正是
non-sealed要谨慎放开的地方











