JDK 17 sealed classes密封类

1,668 阅读4分钟

这是我参与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
  2. 需求:期望超类(图形Shape)可以被访问、但是又不想被扩展(子类仅限于作者定义的已知的图形)

    • Shape 也不能是包访问权限 应该是public:因为期望被开发者访问使用
    • Shape 不能是final:否则作者自定的图形不能扩展
  3. 为了解决上述问题,引入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 ...

  1. permits指定的子类必须在父类的附近

  • 在同一个模块中(module jdk9新增),(父类在一个命名的模块中)

  • 或在同一包中(package),(父类在一个未命名的模块)

  1. 子类在大小和数量上都很小时,可以同父类定义在一个java文件中

  2. permits指定的子类必须直接继承该父类

  3. permits指定的子类在定义时必须使用以下三种修饰符中的一种

  • final:表示该子类是最终的,不能被继承
  • sealed:表示该子类是密封类,可以被指定的其他类继承
  • non-sealed:表示该子类是非密封类,可以被任意其他类继承

4.1子父类在同一模块中

image-20211103032532538

  • 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 {
    }
    
  • 否则会编译错误

    image-20211103032755272

4.2子父类在同一个包中

image-20211103033211779

  • 代码

    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,来和我做朋友吧~❤😘😁🐱‍🐉👀