Java 15 引入了密封类作为一个预览特性,它提供了对继承的细粒度控制。Java 16 提供了一些小的增强,并保持此特性作为预览特性。到了Java 17,密封类和接口成为了标准特性。添加密封类/接口特性的目的在于为开发者提供对继承的细粒度控制。一个密封类可以定义哪些子类型允许扩展它,而其他类则不能扩展它。
以下是关于密封类的一些要点:
-
-
密封类允许使用
permits
关键字声明哪些类可以作为子类型。
-
扩展密封类的类必须声明为
sealed
、non-sealed
或者 final
。
-
密封接口
一个接口可以标记为密封接口使用 sealed
关键字,然后使用 permits
关键字来添加那些可以扩展此接口的接口。
public sealed interface Person permits Employee, Manager {
}
密封接口示例
在这个例子中,我们创建了一个密封接口 Person
,允许 Employee
和 Manager
接口扩展它。Employee
和 Manager
接口具有不同的方法来获取一个人的ID。现在为了获取一个人的ID,我们使用 instanceof
操作符来检查实例是 Employee
还是 Manager
并获取相应的ID。因此我们可以看到,提前了解允许的接口有助于此类场景的开发。
package com.tutorialspoint;
public class Tester {
public static void main(String[] args) {
Person manager = new CorpManager(23, "Robert");
System.out.println("Id: " + getId(manager));
}
public static int getId(Person person) {
if (person instanceof Employee) {
return ((Employee) person).getEmployeeId();
}
else if (person instanceof Manager) {
return ((Manager) person).getManagerId();
}
return -1;
}
}
sealed interface Person permits Employee, Manager {
String getName();
}
non-sealed interface Employee extends Person {
int getEmployeeId();
}
non-sealed interface Manager extends Person {
int getManagerId();
}
class CorpEmployee implements Employee {
String name;
int id;
public CorpEmployee(int id,String name) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public int getEmployeeId() {
return id;
}
}
class CorpManager implements Manager {
String name;
int id;
public CorpManager(int id,String name) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public int getManagerId() {
return id;
}
}
编译并运行上述程序,将会得到如下结果:
Id: 23
密封类
与密封接口相似,也可以使用 sealed
关键字标记一个类为密封类,然后使用 permits
关键字添加可以扩展该类的子类。
public abstract sealed class Person permits Employee, Manager {
}
子类需要有一个修饰符为 sealed
/ final
或 non-sealed
。
public final class Manager extends Person {
}
子类为 non-sealed
是向所有类开放的以供扩展。
public non-sealed class Employee extends Person {
}
约束
在扩展密封类时有一些约束需要注意:
-
-
-
允许的子类必须使用
final
、sealed
或 non-sealed
之一的修饰符。
密封类示例
在这个例子中,我们创建了一个密封抽象类 Person
,允许 Employee
和 Manager
类扩展它。Employee
和 Manager
类具有不同的方法来获取一个人的ID。现在为了获取一个人的ID,我们使用 instanceof
操作符来检查实例是 Employee
还是 Manager
并获取相应的ID。因此我们可以看到,提前知道允许的子类有助于此类场景的开发。
package com.tutorialspoint;
public class Tester {
public static void main(String[] args) {
Person manager = new Manager(23, "Robert");
System.out.println("Id: " + getId(manager));
}
public static int getId(Person person) {
if (person instanceof Employee) {
return ((Employee) person).getEmployeeId();
}
else if (person instanceof Manager) {
return ((Manager) person).getManagerId();
}
return -1;
}
}
abstract sealed class Person permits Employee, Manager {
String name;
String getName() {
return name;
}
}
final class Employee extends Person {
String name;
int id;
Employee(int id, String name){
this.id = id;
this.name = name;
}
int getEmployeeId() {
return id;
}
}
non-sealed class Manager extends Person {
int id;
Manager(int id, String name){
this.id = id;
this.name = name;
}
int getManagerId() {
return id;
}
}
编译并运行上述程序,将会得到如下结果:
Id: 23