JDK 17 sealed classes密封类

这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

欢迎关注公众号OpenCoder,来和我做朋友吧~❤😘😁🐱‍🐉👀

JDK 17 sealed classes密封类

1.简介

  • 密封类(class)和接口(interface)限制哪些其他类或接口可以扩展(extends)或实现(implements)它们。
  • 密封类JDK 15 中作为预览功能提供,并在JDK 16 中作为预览功能进行了改进。
  • 现在在 JDK 17 中,密封类被最终确定,与 JDK 16 没有任何变化。

2.目标

  • 允许类(class)或接口(interface)的作者控制负责实现它的代码。
  • 提供比访问修饰符更具声明性的方式来限制超类的使用。
  • 支持模式匹配(例如switch模式匹配中的案例)

3.动机

为什么要设计密封类(sealed classes)?

  1. 类和接口的继承层次结构

例如,作者想要提供关于常见、已知平面几何图形的一套API

* 图形Shape
    + 圆形Circle
        - 正圆形Round
        - 椭圆形Oval
    + 多边形Polygon
        - 三角形Triangle
        - 四边形Quadrilateral
    + 其他OtherShape
  1. 需求:期望超类(图形Shape)可以被访问、但是又不想被扩展(子类仅限于作者定义的已知的图形)
* Shape 也不能是包访问权限 应该是public:因为期望被开发者访问使用
* Shape 不能是final:否则作者自定的图形不能扩展
  1. 为了解决上述问题,引入sealed classes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
java复制代码public abstract sealed class Shape
permits Circle, Polygon, OtherShape { ... }

public sealed class Circle extends Shape
permits Round, Oval { ... }
public final class Round extends Circle { ... }
public final class Oval extends Circle { ... }

public sealed class Polygon extends Shape
permits Triangle, Quadrilateral { ... }
public final class Triangle extends Polygon { ... }
public final class Quadrilateral extends Polygon { ... }

public non-sealed class OtherShape extends Shape { ... }

4.密封类语法

sealed class 父类 permits 子类1,子类2 ....

​ 表示父类是密封类,指定可以被继承的有子类1,子类2 …

  1. permits指定的子类必须在父类的附近
  • 在同一个模块中(module jdk9新增),(父类在一个命名的模块中)
  • 或在同一包中(package),(父类在一个未命名的模块)
  1. 子类在大小和数量上都很小时,可以同父类定义在一个java文件中
  2. permits指定的子类必须直接继承该父类
  3. permits指定的子类在定义时必须使用以下三种修饰符中的一种
  • final:表示该子类是最终的,不能被继承
  • sealed:表示该子类是密封类,可以被指定的其他类继承
  • non-sealed:表示该子类是非密封类,可以被任意其他类继承

4.1子父类在同一模块中

image-20211103032532538

  • module-info.java
1
2
3
4
java复制代码module sealed_class_demo {
exports org.example.sealed.package1;
exports org.example.sealed.package2;
}
  • 代码
1
2
3
4
5
6
7
8
9
10
11
java复制代码public abstract sealed class SupperClass permits A, B, C {
}

public final class A extends SupperClass {
}

public final class B extends SupperClass {
}

public final class C extends SupperClass {
}
  • 否则会编译错误

image-20211103032755272

4.2子父类在同一个包中

image-20211103033211779

  • 代码
1
2
3
4
5
6
7
8
9
10
11
java复制代码public abstract sealed class SupperClass permits A, B, C {
}

public final class A extends SupperClass {
}

public final class B extends SupperClass {
}

public final class C extends SupperClass {
}

4.3子父类定义在同一个java文件中

  • 子类在大小和数量上都很小时,可以同父类定义在一个java文件中
  • 代码
1
2
3
4
5
java复制代码public abstract sealed class SupperClass {
final class A extends SupperClass{}
final class B extends SupperClass{}
final class C extends SupperClass{}
}

4.4子类修饰符

  • permits指定的子类在定义时必须使用以下三种修饰符中的一种
  • 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java复制代码// 密封类SupperClass 指定子类 A B C
public abstract sealed class SupperClass permits A, B, C {
}

// A不能被继承
public final class A extends SupperClass {
}

// B 继承SupperClass,并指定子类D
public sealed class B extends SupperClass permits D{

}

// D 继承B
public sealed class D extends B{

}

// C 可以被任意其他类继承
public non-sealed class C extends SupperClass {
}

public class Other extends C{}

5.密封接口

  • sealed interface 接口 permits 实现类1,实现类2 ....
  • 代码
1
2
3
4
5
6
7
8
9
10
11
java复制代码public sealed interface Inter permits A,B,C{
}

public final class A implements Inter{
}

public final class B implements Inter{
}

public final class C implements Inter{
}

6.JDK中的密封类

  • ConstantDesc是JDK12 中出现的一组API。定义了一些JVM中已知的符号引用,常量池中的常量描述符
  • JDK17 使用密封类对已知的继承体系做了优化
  • 代码
1
2
3
4
5
6
7
8
9
10
java复制代码public sealed interface ConstantDesc
permits ClassDesc,
MethodHandleDesc,
MethodTypeDesc,
Double,
DynamicConstantDesc,
Float,
Integer,
Long,
String { ... }

7.模式匹配的支持

  • 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
java复制代码sealed interface S permits A, B, C {}
final class A implements S {}
final class B implements S {}
final class C implements S {}

// 错误
static void switchStatementComplete(S s) {
switch (s) { // 编译错误,缺少类型B,自动提示
case A a :
System.out.println("A");
break;
case C c :
System.out.println("C");
break;
};
}
// 正确
static int testSealedCoverage(S s) {
return switch (s) {
case A a -> 1;
case B b -> 2;
case C c -> 3;
};
}

欢迎关注公众号OpenCoder,来和我做朋友吧~❤😘😁🐱‍🐉👀

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%