这是我参与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)?
-
类和接口的继承层次结构
例如,作者想要提供关于常见、已知平面几何图形的一套API
- 图形Shape
- 圆形Circle
- 正圆形Round
- 椭圆形Oval
- 多边形Polygon
- 三角形Triangle
- 四边形Quadrilateral
- 其他OtherShape
- 圆形Circle
- 图形Shape
-
需求:期望超类(图形Shape)可以被访问、但是又不想被扩展(子类仅限于作者定义的已知的图形)
- Shape 也不能是包访问权限 应该是public:因为期望被开发者访问使用
- Shape 不能是final:否则作者自定的图形不能扩展
-
为了解决上述问题,引入sealed classes
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 ...
permits
指定的子类必须在父类的附近
在同一个模块中(module jdk9新增),(父类在一个命名的模块中)
或在同一包中(package),(父类在一个未命名的模块)
子类在大小和数量上都很小时,可以同父类定义在一个java文件中
permits
指定的子类必须直接继承该父类
permits
指定的子类在定义时必须使用以下三种修饰符中的一种
- final:表示该子类是最终的,不能被继承
- sealed:表示该子类是密封类,可以被指定的其他类继承
- non-sealed:表示该子类是非密封类,可以被任意其他类继承
4.1子父类在同一模块中
-
module-info.java
module sealed_class_demo { exports org.example.sealed.package1; exports org.example.sealed.package2; }
-
代码
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.2子父类在同一个包中
-
代码
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文件中
-
代码
public abstract sealed class SupperClass { final class A extends SupperClass{} final class B extends SupperClass{} final class C extends SupperClass{} }
4.4子类修饰符
-
permits
指定的子类在定义时必须使用以下三种修饰符中的一种 -
代码
// 密封类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 ....
-
代码
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 使用密封类对已知的继承体系做了优化
-
代码
public sealed interface ConstantDesc permits ClassDesc, MethodHandleDesc, MethodTypeDesc, Double, DynamicConstantDesc, Float, Integer, Long, String { ... }
7.模式匹配的支持
-
代码
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,来和我做朋友吧~❤😘😁🐱🐉👀