详解 Java 17 中新推出的密封类
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很早就已经有一些了,主要是这两种方式:
final修饰类,这样类就无法被继承了package-private类(非public类),可以控制只能被同一个包下的类继承
但很显然,这两种限制方式的粒度都非常粗,如果有更精细化的限制需求的话,是很难实现的。
新特性:密封类
为了进一步增强限制能力,Java 17中的密封类增加了几个重要关键词:
sealed:修饰类/接口,用来描述这个类/接口为密封类/接口non-sealed:修饰类/接口,用来描述这个类/接口为非密封类/接口permits:用在extends和implements之后,指定可以继承或实现的类
下面我们通过一个例子来理解这几个关键词的用法,更多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的密封要求被传递过来,此时子类就必须在sealed、non-sealed、final之间选择一个定义,它们分别代表:
sealed:继续延续密封类特性,可以继续指定继承的类,并传递密封定义给子类non-sealed:声明这个类为非密封类,可以被任意继承final:不允许继承
根据上面的假设需求,第一、第二层稳定,允许第三层具体英雄角色可以后期不断增加新英雄,所以三类抽象英雄的定义可以这样编写:
public non-sealed class TankHero extends Hero {
}
而对于第三层的英雄角色,已经是最后的具体实现,则可以使用final定义来阻断后续的继承关系,比如这样:
public final class Ezreal extends AttackHero {
}
通过这样的设置,这三层英雄的结构中第一第二层就得到了比较好的保护。
好了,今天的分享就到这里!如果您学习过程中如遇困难?可以加入我们超高质量的技术交流群,参与交流与讨论,更好的学习与进步!另外,不要走开,关注我!持续更新Java新特性专栏,文档形式看Java新特性,阅读学习体验更佳!
欢迎关注我的公众号:程序猿DD。第一时间了解前沿行业消息、分享深度技术干货、获取优质学习资源
详解 Java 17 中新推出的密封类的更多相关文章
- 详解Java 8中Stream类型的“懒”加载
在进入正题之前,我们需要先引入Java 8中Stream类型的两个很重要的操作: 中间和终结操作(Intermediate and Terminal Operation) Stream类型有两种类型的 ...
- 详解Java中的clone方法
详解Java中的clone方法 参考:http://blog.csdn.net/zhangjg_blog/article/details/18369201/ 所谓的复制对象,首先要分配一个和源对象同样 ...
- 【转帖】windows命令行中java和javac、javap使用详解(java编译命令)
windows命令行中java和javac.javap使用详解(java编译命令) 更新时间:2014年03月23日 11:53:15 作者: 我要评论 http://www.jb51.ne ...
- 超全详解Java开发环境搭建
摘自:https://www.cnblogs.com/wangjiming/p/11278577.html 超全详解Java开发环境搭建 在项目产品开发中,开发环境搭建是软件开发的首要阶段,也是必 ...
- 详解Java GC的工作原理+Minor GC、FullGC
详解Java GC的工作原理+Minor GC.FullGC 引用地址:http://www.blogjava.net/ldwblog/archive/2013/07/24/401919.html J ...
- Protocol Buffer技术详解(Java实例)
Protocol Buffer技术详解(Java实例) 该篇Blog和上一篇(C++实例)基本相同,只是面向于我们团队中的Java工程师,毕竟我们项目的前端部分是基于Android开发的,而且我们研发 ...
- java基础(十五)----- Java 最全异常详解 ——Java高级开发必须懂的
本文将详解java中的异常和异常处理机制 异常简介 什么是异常? 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常. Java异常的分类和类结构图 1.Java中的所 ...
- 「跬步千里」详解 Java 内存模型与原子性、可见性、有序性
文题 "跬步千里" 主要是为了凸显这篇文章的基础性与重要性(狗头),并发编程这块的知识也确实主要围绕着 JMM 和三大性质来展开. 全文脉络如下: 1)为什么要学习并发编程? 2) ...
- 异常处理器详解 Java多线程异常处理机制 多线程中篇(四)
在Thread中有异常处理器相关的方法 在ThreadGroup中也有相关的异常处理方法 示例 未检查异常 对于未检查异常,将会直接宕掉,主线程则继续运行,程序会继续运行 在主线程中能不能捕获呢? 我 ...
随机推荐
- “a==b”和”a.equals(b)”有什么区别?
如果 a 和 b 都是对象,则 a==b 是比较两个对象的引用,只有当 a 和 b 指 向的是堆中的同一个对象才会返回 true,而 a.equals(b) 是进行逻辑比较,所以 通常需要重写该方法来 ...
- 学习Kvm(二)
一.走进云计算 云计算:云计算是一种按使用量付费的模式,这种模式提供可用的.便捷的.按需的网络访问, 进入可配置的计算资源共享池(资源包括网络,服务器,存储,应用软件,服务),这些资源能够被快速提供, ...
- centos安装服务参考博客,亲测可用
centos 安装nginx参考 日志log报错 nginx -c /etc/nginx/nginx.conf https://blog.csdn.net/weixin_41004350/articl ...
- 遇到的问题之“Dubbo 直连 Invoke remote method timeout 问题!”
Dubbo 直连 Invoke remote method timeout 问题! 在测试环境消费者直连服务端进行测试时, 其中一个RPC接口抛出一个错误, 如下: Caused by: com. ...
- 前端面试题整理——HTML/CSS
如何理解语义化: 对应的内容是用相应意思的标签,增加开发者和机器爬虫对代码的可读性. 块状元素和内联元素: 块状元素有:display:block/table:有div h1 h2 table ul ...
- java1.7之后的比较器特别之处
在jdk1.7环境下使用Collectons.sort()方法: 比如:Collections.sort(list, new Comparator<Integer>()); 就可能会出现异 ...
- 浅谈arguments属性callee
1.首先 arguments 是一个对应于传递给函数的参数的类数组对象 2. arguments.callee 属性包含当前正在执行的函数. 描述 callee 是 arguments 对象的一个属性 ...
- Python入门-运算符
运算通常可以根据最终获得的值不同,可以分两类,即结果为具体的值,结果为bool值,那么哪些结果为具体的值-->算数运算.赋值运算,哪些结果又为bool值?--->比较运算.逻辑运算和成员运 ...
- 北桥芯片(north bridge/host bridge)
看下上面的图,会比较清晰的认识到北桥芯片所在位置 北桥芯片(North Bridge) 是mother board chipset(主板芯片组) 中起主导作用的最重要的组成部分,也称为主桥(Host ...
- DDD(Domain-Driven Design) 领域驱动设计
DDD(Domain-Driven Design) 领域驱动设计 1. DDD(Domain-Driven Design)是什么? DDD是Eric Evans在2003年出版的<领域驱动设计: ...