密封类(Sealed Class)
Java 17 引入了密封类(Sealed Class),用来限制类的继承关系。
为什么要限制继承?我见过太多项目,因为子类太多导致代码难以维护。一个接口有几十个实现类,switch 语句要写几十个 case,每次加新实现都要改很多地方。
密封类就是为了解决这个问题:在编译期确保只有指定的类可以继承/实现。
今天我们就来把密封类彻底讲透。
一、为什么需要密封类
1.1 继承失控的问题
1.2 switch 的问题
1.3 密封类的解决方案
二、密封类的语法
2.1 密封接口
2.2 密封类
2.3 子类的修饰符规则
三、密封类的检查机制
3.1 编译期检查
编译器会强制检查,不在 permits 列表中的类不能继承/实现。
3.2 switch 的穷尽检查
编译器检查 switch 是否覆盖了所有密封类型的子类型。
3.3 不需要 default 的情况
如果 switch 不是穷尽的,编译器会报错。
四、【直观类比】
【直观类比】
密封类就像一个"家族族谱":
只有族谱上登记的人才能继承,不在名单上的"外人"不能继承。
五、密封类的应用场景
5.1 有限状态机
5.2 领域模型
5.3 API 设计
六、密封类与 Record
6.1 Record 实现密封接口
6.2 密封 Record
Record 也可以是密封的:
七、生产避坑
7.1 ❌ 错误示范:忘记声明所有子类
7.2 ❌ 错误示范:在 permits 列表中写不存在的类
7. ✅ 正确示范:规划好继承层次
八、面试追问链
第一层:基础概念
面试官问:"密封类是什么?"
Java 17 引入的特性,用 sealed 修饰类和接口,用 permits 声明允许的子类。子类的修饰符必须是 final、sealed 或 non-sealed 之一。
第二层:作用
面试官问:"密封类解决了什么问题?"
在编译期确保只有指定的类可以继承/实现,避免类被任意扩展。配合 switch 的穷尽检查,可以让编译器强制开发者处理所有情况。
第三层:与枚举的区别
面试官问:"密封类和枚举有什么区别?"
枚举是"有限实例",密封类是"有限类型"。枚举适合表示固定的几个值,密封类适合表示有多个子类变体的概念。密封类可以有自己的状态(字段),枚举不行。
【学习小结】
- 密封类用
sealed声明,permits指定允许的子类 - 子类必须是
final、sealed或non-sealed - 编译器强制检查,防止未声明的继承
- 配合 switch 的穷尽检查
- 适合有限状态机、领域模型、API 设计