Java 17 新特性揭秘:密封类的华丽登场,面向对象编程再进化

简介: 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 很早就已经有一些了,主要是这两种方式:

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

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

新特性:密封类

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

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

下面我们通过一个例子来理解这几个关键词的用法。

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

  • 坦克
  • 输出
  • 辅助

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

// 英雄基类
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 关键词和 permits 关键来定义 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 {
}

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

相关文章
|
8月前
|
存储 Java 索引
用Java语言实现一个自定义的ArrayList类
自定义MyArrayList类模拟Java ArrayList核心功能,支持泛型、动态扩容(1.5倍)、增删改查及越界检查,底层用Object数组实现,适合学习动态数组原理。
344 4
|
8月前
|
IDE JavaScript Java
在Java 11中,如何处理被弃用的类或接口?
在Java 11中,如何处理被弃用的类或接口?
367 5
|
8月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
400 1
|
8月前
|
Java Go 开发工具
【Java】(8)正则表达式的使用与常用类分享
正则表达式定义了字符串的模式。正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。
505 1
|
8月前
|
存储 Java 程序员
【Java】(6)全方面带你了解Java里的日期与时间内容,介绍 Calendar、GregorianCalendar、Date类
java.util 包提供了 Date 类来封装当前的日期和时间。Date 类提供两个构造函数来实例化 Date 对象。第一个构造函数使用当前日期和时间来初始化对象。Date( )第二个构造函数接收一个参数,该参数是从1970年1月1日起的毫秒数。
323 0
|
Java API Apache
Java 9都有哪些新特性?
Java 9都有哪些新特性?
236 0
|
JavaScript 前端开发 Java
Java 10都有哪些新特性?
Java 10都有哪些新特性?
303 0
|
Java API 数据安全/隐私保护
Java 11都有哪些新特性?
Java 11都有哪些新特性?
211 0
|
搜索推荐 Java 程序员
Java 12都有哪些新特性?
Java 12都有哪些新特性?
287 0
Java 12都有哪些新特性?
|
前端开发 Java 编译器
Java 14 有哪些新特性?
记录为 Java 提供了一种正确实现数据类的能力,不再需要为实现数据类而编写冗长的代码。下面就来看看 Java 14 中的记录有哪些新特性。