Java 新特性-封闭类

概念

在 JDK17 之前,限制一个类的扩展性只有通过私有类或 final 修饰符的方式,但这 2 种方式的局限性较大:私有类只能在一个类的内部使用,final 修饰符的方式则使一个类完全不可扩展。 封闭类在 JDK17 中正式发布,借助它可将类的扩展性限制在可以预测和控制的范围内,封闭类和封闭接口打开了全开放和全封闭两个极端之间的中间地带,为接口设计和实现提供了新的可能性。

封闭类这个概念,涉及到两种类型的类。第一种是被扩展的父类,第二种是扩展而来的子类。通常地,我们把第一种称为封闭类,第二种称为许可类。

如何声明

封闭类的声明使用 sealed 类修饰符,然后在所有的 extends 和 implements 语句之后,使用 permits 指定允许扩展该封闭类的子类。

由 permits 关键字指定的许可子类(permitted subclasses),必须和封闭类处于同一模块(module)或者包空间(package)里。如果封闭类和许可类是在同一个模块里,那么它们可以处于不同的包空间里。如果允许扩展的子类和封闭类在同一个源代码文件里,封闭类可以不使用 permits 语句,Java 编译器将检索源文件,在编译期为封闭类添加上许可的子类。

许可类的声明需要满足下面的三个条件:

  • 许可类必须和封闭类处于同一模块(module)或者包空间(package)里,也就是说,在编译的时候,封闭类必须可以访问它的许可类;
  • 许可类必须是封闭类的直接扩展类;
  • 许可类必须声明是否继续保持封闭:
    • 许可类可以声明为终极类(final),从而关闭扩展性;
    • 许可类可以声明为封闭类(sealed),从而延续受限制的扩展性;
    • 许可类可以声明为解封类(non-sealed), 从而支持不受限制的扩展性。

需要注意的是,由于许可类必须是封闭类的直接扩展,因此许可类不具备传递性。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
* 封闭类 Area
*/
public abstract sealed class Area permits Area.Beijing, Area.Hubei {

public final String name;

public Area(String name) {
this.name = name;
}

/**
* 解封类 Beijing,它是 Area 的许可类
*/
public static non-sealed class Beijing extends Area {

public Beijing(String name) {
super(name);
}

}

/**
* 封闭类 Hubei,它是 Area 的许可类
*/
public static sealed class Hubei extends Area {

public Hubei(String name) {
super(name);
}

}

/**
* 终极类 Shiyan,它是 Hubei 的许可类
*/
public static final class Shiyan extends Hubei {

public Shiyan(String name) {
super(name);
}

}

/**
* Chaoyang 既不是封闭类,也不是许可类
*/
public static class Chaoyang extends Beijing {

public Chaoyang(String name) {
super(name);
}

}

}

上述代码中,Area 是一个封闭类;许可类 Beijing 是一个解封类;许可类 Hubei 是一个封闭类;许可类 Shiyan 是一个终极类;而 Chaoyang 既不是封闭类,也不是许可类。


Java 新特性-封闭类
https://blog.yohlj.cn/posts/4ea3f939/
作者
Enoch
发布于
2023年1月8日
许可协议