Java 17 新特性 - 密封类 sealed class

密封类可以让我们更好的控制哪些类可以对我定义的类进行扩展。密封类可能对于框架或中间件的开发者更有用。在这之前一个类要么是可以被extends的,要么是final的,只有这两种选项。

密封类可以控制有哪些类可以对超类进行继承,在Java 17之前如果我们需要控制哪些类可以继承,可以通过改变类的访问级别,比如去掉类的public,访问级别为默认。比如我们在cn.pottercoding.java17包中定义了如下的三个类:

package cn.pottercoding.java17;
public abstract class Furit {
}
public class Apple extends Furit {
}
public class Pear extends Furit {
}

那么我们可以在另一个包cn.pottercoding.java11中写如下的代码:

private static void test() {
    Apple apple = new Apple();
    Pear pear = new Pear();
    Fruit fruit = apple;
    class Avocado extends Fruit {};
}

既可以定义Apple,Pear,也可以将apple实例赋值给Fruit,并且可以对Fruit进行继承。
如果我们不想让Fruit在cn.pottercoding.java11包以外被扩展,在Java11版本中只能改变访问权限,去掉class的public修饰符。这样虽然可以控制被被继承,但是也会导致Fruit fruit = apple;也编译失败;在Java 17中通过密封类可以解决这个问题。

package cn.pottercoding.java17;

public abstract sealed class Furit permits Apple,Pear {
}
public non-sealed class Apple extends Furit {
}
public final class Pear extends Furit {

}

在定义Furit时通过关键字sealed声明为密封类,通过permits可以指定Apple,Pear类可以进行继承扩展。
子类需要指明它是final,non-sealed或sealed的。父类不能控制子类是否可以被继承。

private static void test() {
    Apple apple = new Apple();
    Pear pear = new Pear();
    // 可以将apple赋值给Fruit
    Fruit fruit = apple;
    // 只能继承Apple,不能继承Furit
    class Avocado extends Apple {};
}