Java 17+模式匹配switch在密封类体系下要求穷尽所有子类型:父类用sealed+permits显式声明全部子类,各子类须为final/sealed/non-sealed;switch直接按子类型绑定解构变量,无需default;支持when守卫,但须确保每种子类至少一个case匹配。

在密封类(sealed classes)体系下使用 Java 的模式匹配 switch(Java 17+),核心是让编译器能**穷尽所有已知子类型**,从而安全地进行类型解构与分支处理。这不是简单把 instanceof 换成 switch,而是要让类型系统和语法协同工作。
确保密封类层级完整且封闭
模式匹配 switch 要求编译器能静态确认所有可能的子类型——这只有在密封类显式列出全部允许子类时才成立。
- 父类必须用 sealed 修饰,并通过 permits 明确声明所有直接子类
- 每个子类必须用 final、sealed 或 non-sealed 做出响应;若无进一步扩展需求,统一用 final 最安全
- 不能有 permits 列表之外的运行时子类,否则 switch 无法覆盖全部情况,编译报错
例如:
sealed interface Expr permits Num, Add, Mul {}record Num(int value) implements Expr {}
record Add(Expr left, Expr right) implements Expr {}
record Mul(Expr left, Expr right) implements Expr {}
用 switch 表达式匹配并解构子类型
声明 switch 时,用 Expr e 作为目标,各 case 直接写子类型名 + 变量绑定,Java 自动完成类型检查与字段解构。
立即学习“Java免费学习笔记(深入)”;
- case 后跟子类名(如 Num n),n 就是自动强转并可用的变量
- 每个 case 必须返回相同类型(若为 switch 表达式),或统一 break(若为语句式 switch)
- 无需 default 分支——只要密封类定义完整,编译器知道已覆盖全部可能,default 会被视为冗余甚至报错
示例(计算表达式值):
int eval(Expr e) {return switch (e) {
case Num n -> n.value();
case Add a -> eval(a.left()) + eval(a.right());
case Mul m -> eval(m.left()) * eval(m.right());
};
}
处理嵌套结构与守卫条件
复杂逻辑中,可在 case 后加 when 子句做运行时判断(守卫),比如区分正负数、空集合等。
- 守卫写在 case 类型绑定之后,用 when (boolean-expr)
- 多个 when 分支需注意顺序:先匹配类型,再判断守卫;守卫不满足则尝试下一个 case
- 仍需保证所有密封子类至少有一个 case 匹配(守卫不能导致某子类完全被跳过)
例如只对正数 Num 求平方,其余照常处理:
case Num n when n.value() > 0 -> n.value() * n.value();case Num n -> n.value();
避免常见陷阱
新手容易卡在几个地方:
- 忘记把子类设为 final 或未在 permits 中列出——编译器无法确认穷尽性,强制要求 default
- switch 表达式里漏写某个子类 case,编译直接失败(不是警告)
- 在 case 中误用原始变量 e(如写 e.toString()),应使用解构后的变量(如 n.value())
- 试图在 case 中 new 一个未声明的子类实例——违反密封约束,编译不通过
不复杂但容易忽略:每次修改密封类继承关系后,所有相关 switch 都要同步检查是否覆盖新增/删减的子类。


















