详解 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中也有相关的异常处理方法 示例 未检查异常 对于未检查异常,将会直接宕掉,主线程则继续运行,程序会继续运行 在主线程中能不能捕获呢? 我 ...
随机推荐
- springboot项目如何添加热部署
环境jdk1.8.maven3.6.使用工具为idea 1.在pom.xml文件中添加依赖 <dependency> <groupId>org.springframework. ...
- Linux文件管理 | Liunx 常用命令
文件与目录基本操作 目录: 一.显示文件内容 cat 命令 more 命令 less 命令 head 命令 tail 命令 二.文件内容查询(grep) 三.文件查找命令 find 命令 locate ...
- CSS入门指南-4:页面布局
这是<CSS设计指南>的读书笔记,用于加深学习效果. display 属性 display是 CSS 中最重要的用于控制布局的属性.每个元素都有一个默认的 display 值.对于大多数元 ...
- H5进阶篇--实现微信摇一摇功能
在HTML5中,DeviceOrientation特性所提供的DeviceMotion事件封装了设备的运动传感器时间,通过改时间可以获取设备的运动状态.加速度等数据(另还有deviceOrientat ...
- Html5 Canvas学习之路(五)
Canvas 图像(上) Canvas 图像API可以加载图像数据,然后直接将图像应用到画布上.还可以裁切.拼贴图像数据,以显示用户需要的部分.此外,Canvas还提供了像素数据的存储功能,这样就能对 ...
- 关于Symbol.iterator 学习笔记
1.可以部署在对象上的一个遍历器 2. 遍历器是一个函数,需要返回一个含有一个next 方法的对象 const likeArray = {0:'a', 1: 'b', 2: 'c',3: 'd'. l ...
- window.location.href用法与a标签的比较
1.在使用这两种方法进行页面的跳转时,这两种方法都能够有效的实现该功能 但是其原理不尽相同 第一:window.location.href()方法必须书写在js中 <html> <h ...
- vue获取验证码倒计时
<template> <div> <el-button :disabled="disabled" @click="sendcode" ...
- Blazor组件自做九: 用20行代码实现文件上传,浏览目录功能 (3)
接上篇 Blazor组件自做九: 用20行代码实现文件上传,浏览目录功能 (2) 7. 使用配置文件指定监听地址 打开 appsettings.json 文件,加入一行 "UseUrls&q ...
- python数据类型与基础运算
注释:了解其他数据类型补充 基础数据类型补充 可以回一下之前的数据类型: 整型,浮点型,字串符和列表. 一.字典(dict) #字典:可以精准的储存数据 是用大括号表示'{}' '字典和数据数据列表差 ...