你必须知道的Java17新特性-密封类(Sealed Classes)

什么是密封类

密封类(Sealed Classes),这个概念在许多语言中都存在。例如,在C#中的密封类表示表明该类是最终类(不可被继承);在Scala中密封类表示case类的子类只能限定在当前源文件中定义;在Kotlin中密封类要求其子类只能在当前源文件中定义。

尽管不同语言中的密封类的概念各不相同,但总的来说都是对子类的继承进行了限制,只不过这个继承的限制范围和程度各不一样。

那么密封类的密封概念就比较清晰了,即:限制类的继承。

为什么需要密封类

对于面向对象语言来说,对象间的继承、实现关系是为了对类能力的扩展和增强。但是当这种增强的能力无法被原系统支持的时候,则会导致系统出现不可预见的异常逻辑。

所以为了避免开发人员错误地重用一些代码,我们需要对类的继承扩展能力进行限制,以确系统的可控。那种控制需要满足两种条件:

  1. 我们需要对继承关系进行限制

  2. 当我们突破限制的时候需要显示的进行,让用户知晓潜在的风险。

其中第一点是对无序扩展的限制,第二点是在需要进行扩展的时候,仍然可以基于其一种扩展能力,但是风险并不通过提供能力的组件承担,而是用进行声明的用户进行承担。

显然这两种能力中,第一种能力是必须的,第二种能力是扩展的。在第一节中的三种语言中实现的密封类都是实现了第一种控制需求,并没有对第二种进行扩展。

JAVA中的密封

如果是针对于密封类的基本特性来说,Java在很早以前就已经支持了这种特性,而实现这种能力的方式有如下两种:

  1. 利用final关键字修饰类

  2. 使用包私有类

其中,通过final关键字修饰可以将类描述为“最终态”,此时的final类是无法被继承的,这种将类描述为最终态的形式,是和C#的密封类的特性一致的。

而使用包私有类让该类的子类仅在该包下进行继承,这种限制的形态类似于Scala与Kotlin的限制条件:允许满足特定情况的继承。

所以,从广义的密封概念上来讲,Java很早就支持了对于对类密封的概念,但是与上文举例的其他语言一样,其仅仅进行了类的限制,没有对用户开放选择性。

威力加强的新特性 Sealed Classes

针对于这种扩展的能力需求,Java引入了密封类的概念。

密封类(Sealed Classes)的首次提出是在Java15 的 JEP 360中,并在Java 16 的 JEP 397 再次预览,而在Java 17的 JEP 409 成为正式的功能。从基本概念上来说,三个版本中的密封类并不不同,如果是已经在之前预览版本中对密封类有了解的同学可以大胆使用了!

密封类

首先Java中密封类(Sealed Classes)的核心是: 通过sealed修饰符来描述某个类为密封类,同时使用permits关键字来制定可以继承或实现该类的类型有哪些。注意sealed可以修饰的是类(class)或者接口(interface),所以permits关键字的位置应该在extends或者implements之后。

以下为描述一个接口为密封类的写法实例:

public sealed interface dogService extends animalService permits dogServiceImpl {

    void doSomething();

}

密封类的子类

密封类支持三种形式的子类

  • 密封类
public sealed class dogServiceImpl implements dogService permits moreDogService {

    @Override
    public void doSomething() {
    }
}
  • final修饰的最终态类
public final class dogServiceImpl implements dogService {

    @Override
    public void doSomething() {
    }
}
  • 使用non-sealed显示的表示为非密封的类
public non-sealed class dogServiceImpl implements dogService {

    @Override
    public void doSomething() {
    }

    static class bigDogExtend extends dogServiceImpl {
    }
}

首先,对于密封类来说,其子类如果仍然是密封的类,说明由下游调用方继续提供密封保障。而如果是最终态类的话,则指定类已经形成完全密封,所以满足密封保障。而第三种使用non-sealed关键字对类进行显式的声明其不进行密封,这种情况下由下游调用方承担打破密封的风险(但是我是觉得竟然java都开始使用包含‘-’的关键词了,太丑陋了我无法接受)。

从密封性的角度上来说,sealed子类传递了密封性;final的子类确认密封性;non-sealed显式放弃密封性。

我们可以发现,第三种non-sealed类型的关键字便为用户提供了一种可以当用户认同风险的情况下突破限制的手段,所以我们认为在密封灵活性的方面Sealed Classes能力在保持密封特性的前提下提供了极大的扩展性。

注意,由于要保证密封,所以类与类之间的密封传递是不能跨越继承层级的,即:

对类的继承,子类必须为permits关键字声明类的直接实现类。

这部分各位可以自己试一下。

同样的,由于密封类的实现是为了控制继承关系,所以密封类不支持隐式的继承关系,所以:

密封类不支持匿名类与函数式接口。

最后

总结一下,Java 本身支持粗粒度的类的密封性保障。而在此基础上密封类提供了更细粒度的继承关系控制。密封类的主要新增关键词有sealedpermitsnon-sealed。子类继承方式sealed传递了密封性,final确认了密封性,non-sealed显式声明破坏密封性。给予密封性的控制,所以要求子类必须为permits后声明的直接子类,所以也不支持匿名类与函数式接口。

作为Java 17中转正的功能,这是十分重要的特性之一,值得好好学习一下。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容