【JDK17 | 14】Java 17 深入剖析:密封类

embedded/2024/10/10 20:26:42/

引言

Java 17引入了一项重要的新特性——密封类(Sealed Classes),这标志着Java在面向对象编程领域的又一次重大进步。密封类提供了一种机制来精确控制类的继承链,使得类的设计者能够明确规定哪些类能够继承或实现该类。

一、密封类的作用

在面向对象编程中,继承是一种常见的行为,它允许我们复用代码并扩展现有功能。然而,有时候我们希望限制这种继承行为,以确保类的使用不会超出我们的预期。密封类正是为了解决这个问题而设计的,它限制了类的继承,使得类的继承更加可预测和安全。

二、已有的限制手段

在Java中,我们已经有几种方式来限制类的继承:

  1. 使用final关键字修饰类,这样类就无法被继承。
  2. 将类设置为非public(即package-private),这样类只能被同一个包下的类继承。

但这两种方式的粒度都比较粗,如果需要更精细的控制,就显得力不从心了。

三、新特性:密封类

Java 17中的密封类引入了几个重要的关键词:

  • sealed:修饰类或接口,表示该类或接口是密封的。
  • non-sealed:修饰类或接口,表示该类或接口不是密封的。
  • permits:用在extendsimplements之后,指定可以继承或实现的类。

四、实战应用

4.1定义密封类

假设我们要设计一个游戏,游戏中的英雄分为三大类:坦克、输出和辅助。每个种类下又有各种不同的具体英雄。我们可以使用密封类来定义这样的结构:

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

通过这种方式,我们确保了Hero类的继承是受控的,只有TankHeroAttackHeroSupportHero可以继承它,而具体的英雄实现则被标记为final,防止进一步的继承。

4.2密封类与模式匹配

密封类与Java的模式匹配(Pattern Matching)相结合,可以提供更强的类型安全和代码清晰度。例如,我们可以在switch语句中使用模式匹配来处理密封类的不同子类:

java">Shape rotate(Shape shape, double angle) {return switch (shape) {case Circle c -> c;case Rectangle r -> shape.rotate(angle);case Square s -> shape.rotate(angle);};
}

这种模式匹配确保了所有可能的子类都被覆盖,如果缺少任何一个子类,编译器将会发出错误。

五、应用场景

5.1. 图形库设计

在设计图形库时,我们可能只想允许特定的几何形状类继承一个基类。例如,我们有一个Shape基类,我们只想允许CircleSquare继承它:

java">public sealed class Shape permits Circle, Square {// Shape类的实现
}public final class Circle extends Shape {// Circle类的实现
}public final class Square extends Shape {// Square类的实现
}

在这个场景中,密封类确保了Shape类的继承是受控的,防止了意外的类扩展,提高了库的可靠性和一致性。

5.2. 游戏角色设计

在游戏开发中,我们可能需要定义不同类型的角色,例如坦克、输出和辅助角色,并且每个类别下有具体的实现。使用密封类可以确保角色类的继承结构清晰:

java">public sealed class Hero permits TankHero, AttackHero, SupportHero {// 英雄基类的实现
}public non-sealed class TankHero extends Hero {// 坦克英雄的实现
}public non-sealed class AttackHero extends Hero {// 输出英雄的实现
}public non-sealed class SupportHero extends Hero {// 辅助英雄的实现
}

在这个例子中,Hero类被密封,并且只有TankHeroAttackHeroSupportHero可以继承它。这样的设计有助于维护游戏角色的一致性和可管理性。

5.3. 表达式解析

在构建表达式解析器时,我们可能需要定义一个表达式接口,并且只允许特定的表达式类实现它。例如,一个简单的数学表达式解析器可能只允许ConstantExprPlusExprTimesExpr实现Expr接口:

java">public sealed interface Expr permits ConstantExpr, PlusExpr, TimesExpr {int eval();
}public final class ConstantExpr implements Expr {int value;public ConstantExpr(int value) {this.value = value;}public int eval() {return value;}
}public final class PlusExpr implements Expr {Expr left, right;public PlusExpr(Expr left, Expr right) {this.left = left;this.right = right;}public int eval() {return left.eval() + right.eval();}
}

在这个场景中,密封接口限制了表达式的类型,使得表达式的处理更加安全和可预测。

六、实战指南

6.1定义密封类

要定义一个密封类,你需要使用sealed关键字,并在permits子句中指定允许的子类:

java">public sealed class MyClass permits ClassA, ClassB {// 类的实现
}

6.2 定义密封接口

定义密封接口的方式与密封类类似,但是用于接口:

java">public sealed interface MyInterface permits ClassA, InterfaceB {// 接口的定义
}

6.3 使用模式匹配

Java的模式匹配可以用来处理密封类的不同子类,提高代码的可读性和安全性:

java">public void handleShape(Shape shape) {switch (shape) {case Circle circle -> System.out.println("Circle with radius " + circle.radius);case Square square -> System.out.println("Square with side " + square.side);}
}

6.4 兼容性和反射

密封类与Java的反射API兼容,你可以使用isSealed()getPermittedSubclasses()方法来检查密封类的状态和获取允许的子类列表:

java">if (Shape.class.isSealed()) {System.out.println("Shape is sealed.");Class<?>[] subclasses = Shape.class.getPermittedSubclasses();System.out.println("Permitted subclasses: " + Arrays.toString(subclasses));
}

七、总结

密封类为Java带来了一种新的控制继承的方式,它提高了代码的安全性和可维护性。通过限制类的继承,我们可以构建更加健壮和可预测的系统。随着Java语言的不断发展,密封类将成为面向对象编程中不可或缺的一部分。


http://www.ppmy.cn/embedded/125520.html

相关文章

Unity转Unreal5之从入门到精通 Spline(样条曲线)组件的使用

文章目录 前言实现一个沿路径运动的功能1.新建一个基于 Actor 的蓝图MoveActor,2.并添加 SplineComponent样条组件3.新建 2 个变量,4.在 Tick 事件中设置物体的位置和旋转,蓝图代码如下5.编辑样条曲线6.将上面的蓝图拖进关卡,修改物体的移动速度。7.运行后,该角色就会沿着…

Windows 下纯手工打造 QT 开发环境

用过 QtCreator 和 VS QT 插件&#xff0c;都觉得不是很理想。所以有了这个想法。 手工打造的 QT 的开发环境&#xff0c;是不需要安装上面两个程序的。 1、下载 vcpkg&#xff0c;编译 QT6 下载地址&#xff1a;https://github.com/microsoft/vcpkg.git 进入到 …

Qt 5开发步骤及实例

目录 界面设计编写相应的计算圆面积代码 界面设计 创建桌面应用程序 得到这样一个树形视图 双击界面文件中的dialog.ui 直接双击控件label改名&#xff0c;然后修改最后一个label的属性 修改这个标签的样式&#xff0c;把frameshape改成Panel&#xff0c;frameshadow改…

Visdom可视化——教程

This is a simple tutorial to start using Visdom to plot graphs when using PyTorch. 这是教程链接。

广州自闭症寄宿学校有哪些?选择最适合孩子的学校

在广州这座繁华而充满人文关怀的城市里&#xff0c;有一群特殊的孩子&#xff0c;他们被称为“星星的孩子”——自闭症儿童。他们生活在自己的世界里&#xff0c;对外界的刺激反应迟钝或过度敏感&#xff0c;社交互动困难&#xff0c;语言表达受限。然而&#xff0c;在广州&…

全闪 SDS 一体机提供 FC 能力承载医院核心业务

摘要&#xff1a;邹平市人民医院使用 X3000 SDS 一体机组建分布式存储集群&#xff0c;通过 FC 接口 与 VMware 集群连接&#xff0c;以全闪池承载核心业务&#xff0c;对象存储承载 PACS 数据&#xff0c;实现存储架构的升级改造。 “新医改”的不断推进&#xff0c;对医院的…

计算机视觉的应用36-人工智能时代计算机视觉技术在电力系统中的应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用36-人工智能时代计算机视觉技术在电力系统中的应用。本文综述了人工智能时代计算机视觉技术在电力系统中的应用。文章首先介绍了项目背景&#xff0c;随后详细阐述了计算机视觉技术的模型、技术原理…

【I/O多路复用】阻塞非阻塞I/O

IO复用的本质是不在任何地方阻塞&#xff01; 总结&#xff1a;非阻塞情况下&#xff0c;要配合循环使用。 阻塞&非阻塞IO 阻塞:在进/线程中&#xff0c;发起一个调用时&#xff0c;在调用返回之前&#xff0c;进/线程会被阻塞等待&#xff0c;等待中的进/线让出CPU的使用…