Java 17推出的新特性Sealed Classes经历了2个Preview版本(JDK 15中的JEP 360、JDK 16中的JEP 397),最终定稿于JDK 17中的JEP 409。Sealed Classes有两种主流翻译:密封类、封闭类。个人喜欢前者多一些,所以在本文中都称为密封类。其实Sealed Classes的其他许多语言中并不是什么新鲜事物,C#、Scala等高级语言中都有类似的名称,但意义和作用各不相同。下面就来一起认识一下Java 17中的Sealed Classes。

密封类的作用

在面向对象语言中,我们可以通过继承(extend)来实现类的能力复用、扩展与增强。但有的时候,有些能力我们不希望被继承了去做一些不可预知的扩展。所以,我们需要对继承关系有一些限制的控制手段。而密封类的作用就是限制类的继承

已有的限制手段

对于继承能力的控制,Java很早就已经有一些了,主要是这两种方式:

  1. final修饰类,这样类就无法被继承了
  2. package-private类(非public类),可以控制只能被同一个包下的类继承

但很显然,这两种限制方式的粒度都非常粗,如果有更精细化的限制需求的话,是很难实现的。

新特性:密封类

为了进一步增强限制能力,Java 17中的密封类增加了几个重要关键词:

  • sealed:修饰类/接口,用来描述这个类/接口为密封类/接口
  • non-sealed:修饰类/接口,用来描述这个类/接口为非密封类/接口
  • permits:用在extendsimplements之后,指定可以继承或实现的类

下面我们通过一个例子来理解这几个关键词的用法,更多Java新特性,欢迎关注Java前沿专栏,文档形式看Java新特性,阅读学习体验更佳,持续更新,收藏保存!

假设我们要设计一个游戏,这个游戏给用户选择的英雄种类分为三大类:

  • 坦克
  • 输出
  • 辅助

每个种类下又有各种不同的具体英雄。所以,从我们传统的面向设计思路,会这样来创建:

// 英雄基类
public class Hero { } // 坦克英雄的抽象
public class TankHero extends Hero { } // 输出英雄的抽象
public class AttackHero extends Hero { } // 辅助英雄的抽象
public class SupportHero extends Hero { } // 坦克英雄:阿利斯塔
public class Alistar extends TankHero { } // 输出英雄:伊泽瑞尔
public class Ezreal extends AttackHero { } // 辅助英雄:索拉卡
public class Soraka extends SupportHero { }

整体结构有三层,具体如下图所示:

  • 第一层:Hero是所有英雄的基类,定义英雄的基础属性
  • 第二层:按英雄的分类的三个不同抽象,定义同类英雄的公共属性
  • 第三层:具体英雄的定义

这个时候,为了避免开发人员在创建新英雄的时候,搞乱这样的三层结构。就可以通过引入密封类的特性来做限制。

假设我们希望第一、第二层是稳定的,对于第二层英雄种类的抽象不允许再增加,此时我们就可以这样写:

public sealed class Hero permits TankHero, AttackHero, SupportHero {

}

通过sealed关键词和permitspermits关键来定义Hero是一个需要密封的类,并且它的子类只允许为TankHero, AttackHero, SupportHero这三个。

完成这个改造之后,我们会发现TankHero, AttackHero, SupportHero这三个类开始报错了,具体错误如下:

sealed, non-sealed or final modifiers expected

这是因为父类Hero被sealed修饰之后,sealed的密封要求被传递过来,此时子类就必须在sealednon-sealedfinal之间选择一个定义,它们分别代表:

  • sealed:继续延续密封类特性,可以继续指定继承的类,并传递密封定义给子类
  • non-sealed:声明这个类为非密封类,可以被任意继承
  • final:不允许继承

根据上面的假设需求,第一、第二层稳定,允许第三层具体英雄角色可以后期不断增加新英雄,所以三类抽象英雄的定义可以这样编写:

public non-sealed class TankHero extends Hero {

}

而对于第三层的英雄角色,已经是最后的具体实现,则可以使用final定义来阻断后续的继承关系,比如这样:

public final class Ezreal extends AttackHero {

}

通过这样的设置,这三层英雄的结构中第一第二层就得到了比较好的保护。

好了,今天的分享就到这里!如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!另外,不要走开,关注我!持续更新Java新特性专栏,文档形式看Java新特性,阅读学习体验更佳!

欢迎关注我的公众号:程序猿DD。第一时间了解前沿行业消息、分享深度技术干货、获取优质学习资源

详解 Java 17 中新推出的密封类的更多相关文章

  1. 详解Java 8中Stream类型的“懒”加载

    在进入正题之前,我们需要先引入Java 8中Stream类型的两个很重要的操作: 中间和终结操作(Intermediate and Terminal Operation) Stream类型有两种类型的 ...

  2. 详解Java中的clone方法

    详解Java中的clone方法 参考:http://blog.csdn.net/zhangjg_blog/article/details/18369201/ 所谓的复制对象,首先要分配一个和源对象同样 ...

  3. 【转帖】windows命令行中java和javac、javap使用详解(java编译命令)

    windows命令行中java和javac.javap使用详解(java编译命令) 更新时间:2014年03月23日 11:53:15   作者:    我要评论 http://www.jb51.ne ...

  4. 超全详解Java开发环境搭建

    摘自:https://www.cnblogs.com/wangjiming/p/11278577.html 超全详解Java开发环境搭建   在项目产品开发中,开发环境搭建是软件开发的首要阶段,也是必 ...

  5. 详解Java GC的工作原理+Minor GC、FullGC

    详解Java GC的工作原理+Minor GC.FullGC 引用地址:http://www.blogjava.net/ldwblog/archive/2013/07/24/401919.html J ...

  6. Protocol Buffer技术详解(Java实例)

    Protocol Buffer技术详解(Java实例) 该篇Blog和上一篇(C++实例)基本相同,只是面向于我们团队中的Java工程师,毕竟我们项目的前端部分是基于Android开发的,而且我们研发 ...

  7. java基础(十五)----- Java 最全异常详解 ——Java高级开发必须懂的

    本文将详解java中的异常和异常处理机制 异常简介 什么是异常? 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常. Java异常的分类和类结构图 1.Java中的所 ...

  8. 「跬步千里」详解 Java 内存模型与原子性、可见性、有序性

    文题 "跬步千里" 主要是为了凸显这篇文章的基础性与重要性(狗头),并发编程这块的知识也确实主要围绕着 JMM 和三大性质来展开. 全文脉络如下: 1)为什么要学习并发编程? 2) ...

  9. 异常处理器详解 Java多线程异常处理机制 多线程中篇(四)

    在Thread中有异常处理器相关的方法 在ThreadGroup中也有相关的异常处理方法 示例 未检查异常 对于未检查异常,将会直接宕掉,主线程则继续运行,程序会继续运行 在主线程中能不能捕获呢? 我 ...

随机推荐

  1. 什么是 Idempotence 以及它在哪里使用?

    幂等性是能够以这样的方式做两次事情的特性,即最终结果将保持不变,即好像 它只做了一次. 用法:在远程服务或数据源中使用 Idempotence,这样当它多次接收指令时,它 只处理指令一次.

  2. Spring Cloud第一次请求报错问题

    一.原因 我们在使用Spring Cloud的Ribbon或Feign来实现服务调用的时候,第一次请求经常会经常发生超时报错,而之后的调用就没有问题了.造成第一次服务调用出现失败的原因主要是Ribbo ...

  3. spring 支持哪些 ORM 框架 ?

    Hibernate iBatis JPA JDO OJB

  4. 学习Keepalived(二)

    一.keepalived简介 keepalived是集群管理中保证集群高可用的一个服务软件,其功能类似于,用来防止单点故障. 二.vrrp协议2.1 vrrp协议简介 在现实的网络环境中,两台需要通信 ...

  5. 学习Squid(三)

    Squid 缓存服务 1.缓存服务器结束 缓存服务器(cache server),即用来存储(介质为内存及硬盘)用户访问的网页.图片.文件等等信息的专用服务器,这种服务器不仅可以使用户可以最快的得到他 ...

  6. list集合的快速筛选条件方法

    List<String> list = new ArrayList<>();list.add("张无忌");list.add("周芷若" ...

  7. (Math.round(num*100)/100).toFixed(2); 将输入的数字变成保留两位小数

    <input type="number" @input="onInputPrice" @blur="onPrice" data-id= ...

  8. PAT B1066图像过滤

    输入样例: 3 5 100 150 0 3 189 254 101 119 150 233 151 99 100 88 123 149 0 255   输出样例: 003 189 254 000 00 ...

  9. 【c++】容器的基本操作

    操作\容器 vector list string set stack queue map 插入 push_bcak().insert() push_back() .push_front().inser ...

  10. Python中使用模块和库编程

    """ python中使用模块和库编程 导入模块 import modulename [as alias] from modulename import fun1,fun ...