Java 中的密封类

2024年9月10日 | 阅读 6 分钟

在编程中,安全性和控制流是开发应用程序时必须考虑的两个主要问题。有各种控制特性,例如 final 和 protected 关键字的使用会限制用户访问变量和方法。Java 15 引入了一个新的预览功能,允许我们控制继承。在本节中,我们将通过适当的示例讨论预览功能、密封类和接口的概念

Java 密封类

Java 15 引入了密封类的概念。这是一个预览功能。Java 密封类和接口限制了哪些类和接口可以扩展或实现它们。

换句话说,我们可以说,一个不能被继承但可以被实例化的类称为密封类。它允许类和接口对其允许的子类型拥有更多控制权。它对于通用域建模和为库构建更安全的平台都很有用。

请注意,密封类的概念是预览功能,而不是永久功能。

预览功能

一种其设计、实现和规范已完成但尚未永久化的功能。在未来的 Java SE 版本中,该功能可能以不同形式存在,也可能不存在。

此外,请注意,具有预览功能的代码无法轻松编译和运行。它需要额外的命令行选项。

使用预览功能

如果我们在 Java 程序中使用预览功能,我们必须在编译器和运行时系统中显式启用该预览功能。如果我们不启用预览功能,我们将收到错误消息“预览功能默认禁用”。

使用以下命令编译具有预览功能的 Java 程序

其中 n 是 JDK 版本。

假设 Demo.java 是一个包含预览功能的源文件,我们想编译并运行它。

当我们编译上述源文件时,控制台会收到以下警告消息:

注意:Demo.java 使用预览语言功能。

注意:使用 -Xlint:preview 重新编译以获取详细信息

使用以下命令运行具有预览功能的 Java 程序

注意:使用旧版本 Java SE 的预览功能编写的代码不一定能在新版本中编译或运行。

密封类的用途

密封类与以下内容配合效果良好

  • Java 反射 API
  • Java Records
  • 模式匹配

密封类和接口的优势

  • 它允许子类扩展密封的超类。
  • 它使超类可广泛访问,但不可广泛扩展。
  • 它允许编译器对类用户强制执行类型系统。
  • 超类的开发者可以控制子类。因此,他们可以以更受限制的方式定义方法。

定义一个密封类

密封类的声明并不复杂。如果我们要将一个类声明为密封类,请在其声明中添加sealed修饰符。在类声明和 extends 和 implements 子句之后,添加permits子句。该子句指定了可以扩展密封类的类。

它包含以下修饰符和子句

  • sealed:它只能被其允许的子类扩展。
  • non-sealed:它可以被未知的子类扩展;密封类不能阻止其允许的子类这样做。
  • permits:它允许子类继承和扩展。
  • final:允许的子类必须是 final,因为它阻止了进一步的扩展。

例如,以下 Subjects 类的声明指定了四个允许的子类:English、Science、Mathematics 和 Physics。

Subjects.java

让我们在与密封类相同的模块或包中定义四个允许的子类:English、Science、Mathematics 和 Physics

English.java

Science.java

Mathematics.java

Mathematics 类有一个进一步的子类 AppliedMathematics

AppliedMathematics.java

Physics.java

另一方面,我们也可以在同一个文件中定义允许的子类。在这种情况下,我们可以省略 permits 子句

允许子类的约束

如果一个类被定义为密封类,它会对其允许的子类施加以下三个限制:

1. 所有允许的子类必须与密封类属于同一个模块或包。例如

假设我们有相同的未命名模块和以下包

我们将收到错误“该类不允许从另一个包或模块扩展密封类。”

2. 每个允许的子类都必须显式扩展密封类。

3. 每个允许的子类都必须定义一个修饰符:final、sealed 或 non-sealed。

密封接口

与密封类一样,我们也可以通过在接口名称前添加 sealed 修饰符来定义一个密封接口。之后,使用 extends 关键字(如果需要),然后定义 permits 子句。

该接口只允许 Mango 和 Pineapple 实现它。

让我们通过一个 Java 程序来理解密封类的概念。

注意:在执行以下程序之前,请确保您的系统已安装 Java 15 或更高版本。否则,您将收到错误。

密封类示例

SealedClassExample.java

输出

The age of grandfather is: 87