1. 设计初衷

核心目标:允许类/接口的创建者精确控制继承关系,限制只有特定类能扩展或实现它们。

解决了那些问题?
• 传统Java继承模型过度开放,final 完全禁止继承,包级私有访问限制又无法跨包共享。
• 需明确表达“固定类型层次”的领域模型。
• 为模式匹配(如 switch 表达式)提供穷尽性检查的基础(编译器可验证所有子类覆盖)。

2. 使用语法

// 声明密封类/接口
public abstract sealed class Shape
    permits Circle, Rectangle, Square {...}  // 显式列出允许的子类

// 子类必须用以下修饰符之一:
public final class Circle extends Shape {...}         // 禁止进一步扩展
public sealed class Rectangle extends Shape {...}     // 继续密封(需指定子类)
public non-sealed class WeirdShape extends Shape {...} // 开放扩展(打破密封)
关键规则:

• permits 列表:子类必须在同一模块(或同一包),且需直接继承。

• 子类修饰符:子类必须显式声明 final、sealed 或 non-sealed。

• 省略 permits:若所有子类与密封类在同一源文件,可省略 permits(编译器自动推断)。

3. 面向对象中的应用场景

• 固定类型层次建模:例如图形库的 Shape 仅允许 Circle、Rectangle、Square 子类,避免未知子类破坏逻辑。
• 模式匹配配合:

 // 编译器可验证覆盖所有密封子类(无需default)
  return switch (shape) {
      case Circle c -> c;
      case Rectangle r -> r.rotate();
      case Square s -> s.rotate();
  };

• 记录类(Record)结合:

// 密封类 + 记录类 = 代数数据类型(乘积类型 + 求和类型),如:
sealed interface Expr permits ConstantExpr, PlusExpr {...}
record PlusExpr(Expr a, Expr b) implements Expr {...}  // 记录类隐式final

4. 底层实现原理

1. 编译器验证:

• 强制检查子类是否符合 permits 列表、修饰符约束和访问规则。

• 转换检查:如 Shape 密封时,if (shape instanceof I) 可能编译报错(若无子类实现 I)。

2. JVM层支持:

• PermittedSubclasses 属性:在密封类的 .class 文件中存储允许的子类列表。
PermittedSubclasses_attribute {
u2 number_of_classes;
u2 classes[number_of_classes]; // 指向允许的子类
}
• 运行时拦截:JVM在加载子类时验证其是否在 PermittedSubclasses 列表中,否则抛出 IncompatibleClassChangeError。

• 反射API扩展:

• Class.isSealed():判断类/接口是否密封。

• Class.getPermittedSubclasses():返回允许的子类数组(可能为空)。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐