天天看点

Java类(接口)的新类型——密封类

Java类(接口)的新类型——密封类

密封类是java 17正式支持的一个新特性,它让java中类的继承可以更加细粒度的进行控制。今天就来认识一下这个新的功能。

在以往的java类继承中,java类的继承控制非常有限,仅能通过​<code>​final​</code>​关键字和访问控制符来控制类的继承。例如​<code>​final​</code>​类无法被集成;包私有类仅仅只能在该包下进行继承。

这显然是不够的。如果一个功能只允许出现在​<code>​phone​</code>​和​<code>​pad​</code>​上,不允许出现在​<code>​computer​</code>​上。如果不对该功能的继承实现进行限制,开发人员将很容易滥用该功能的实现类,错误地重用一些代码。这就是密封类产生的原因。

❝ 密封类不仅仅可以是类,也可以是接口。文章中的密封类为统称

密封类(接口)可以明确哪些类和接口可以对其扩展或实现。你可以通过​<code>​sealed​</code>​修饰符来表明某个类是密封类。但是下面是一个错误的密封类声明:

密封类(接口)在声明的时候必须明确可继承(实现)的范围,所以上面的写法是错误的。必须用​<code>​permits​</code>​子句指定允许扩展密封类的类,而且​<code>​permits​</code>​关键字位于​<code>​extends​</code>​或者​<code>​implements​</code>​之后。

简而言之,密封类明确了哪些其他类(或接口)可以扩展它们。

下面是正确的写法:

在上面示例中,密封类(接口)的实现类用了​<code>​final​</code>​关键字标记,当然密封类的实现类还可以是密封类:

那么难道密封类(接口)的子类只能是​<code>​final​</code>​类或者密封类,就不能再扩展了?答案是否定的,只需要使用关键字​<code>​non-sealed​</code>​显式声明密封类的继承实现为非密封类就可以继续扩展了。

总结一下,密封类的子类要么是final class;要么是sealed class;要么是non-sealed class。

密封类​<code>​permits​</code>​关键字声明的子类必须是直接实现类,为了证明这一点我们这样写:

我使用​<code>​sonservice​</code>​间接实现了​<code>​sealedservice​</code>​,结果报错,报错信息要求必须是直接的继承关系。

Java类(接口)的新类型——密封类

错误的密封类继承实现

从上图可以看出​<code>​sonservice​</code>​并非直接实现​<code>​sealedservice​</code>​,这样会打破密封类的规则,所以无法编译通过。

密封类中​<code>​permits​</code>​关键字声明的子类必须是直接子类,不可间接实现。

由于密封类必须明确继承实现关系,所以它不支持匿名类。

同样也不支持函数式接口:

密封类已经在java 17中正式转正,这也是java 17的非常重要的特性之一。对于需要细粒度控制继承关系的场景来说是非常有用的。