Java 简明教程

Java - Sealed Classes and Interfaces

Java 15 引入了 sealed class 作为预览功能,它对 inheritance 提供了细粒度的控制。Java 16 提供了一些次要增强并保留此功能作为预览。在 Java 17 中, sealed class 和接口是标准功能。向 Java 中添加了 sealed class/interface 功能,以便为开发人员提供对继承的细粒度控制。 sealed class 可以定义允许扩展它的子类型,而其他类不能扩展它。

以下是密封类需要考虑的重要事项:

  1. 被密封类使用 sealed 关键字被声明。

  2. 被密封类允许使用 permits 关键字对其可以成为其子类型的类进行声明。

  3. 类扩展被密封类必须被声明为 sealed、non-sealed 或 final。

  4. 被密封类帮助在继承中创建有限且可确定的类层次结构。

Sealed Interface

可以使用 sealed 关键字将 interface 标记为 sealed interface ,然后使用 permits 关键字,我们可以添加可以扩展此接口的接口。

public sealed interface Person permits Employee, Manager {
}

Sealed Interface Example

在此示例中,我们创建了一个密封接口 Person,它允许 Employee 和 Manager 接口进行扩展。Employee 和 Manager 接口具有不同的方法来获取人员的 ID。现在,为了获取人员的 ID,我们使用 instanceof 运算符来检查一个实例是否是 Employee 或 Manager,并获取相应的 ID。因此,我们可以看到,预先知道允许的接口有助于针对此类场景进行开发。

package com.tutorialspoint;

public class Tester {
   public static void main(String[] args) {
      // create an instance of Manager
      Person manager = new CorpManager(23, "Robert");

      // get the id
      System.out.println("Id: " + getId(manager));
   }
   public static int getId(Person person) {
      // check if person is employee then return employee id
      if (person instanceof Employee) {
         return ((Employee) person).getEmployeeId();
      }
      // if person is manager then return manager id
      else if (person instanceof Manager) {
         return ((Manager) person).getManagerId();
      }
      return -1;
   }
}

// a sealed interface Person which is to be inherited by Employee
// and Manager interfaces
sealed interface Person permits Employee, Manager {
   String getName();
}

// Employee and Manager interfaces have to extend Person and can be sealed or non-sealed
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 Class

类似于密封接口,可以使用 sealed 关键字将 class 标记为 sealed class,然后使用 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 {
}

Constraints

在扩展密封类时,我们需要注意到对密封类的使用有一些限制。

  1. 允许的子类应与密封类位于同一模块中。

  2. 允许的子类必须扩展密封类。

  3. 允许的子类必须使用 final、sealed 或 non-sealed 修改符中的任何一个。

Sealed Class Example

在此示例中,我们创建了一个密封抽象类 Person,它允许 Employee 和 Manager 类进行扩展。Employee 和 Manager 类具有不同的方法来获取人员的 ID。现在,为了获取人员的 ID,我们使用 instanceof 运算符来检查一个实例是否是 Employee 或 Manager,并获取相应的 ID。因此,我们可以看到,预先知道允许的子类有助于针对此类场景进行开发。

package com.tutorialspoint;

public class Tester {
   public static void main(String[] args) {
      // create an instance of Manager
      Person manager = new Manager(23, "Robert");

      // get the id
      System.out.println("Id: " + getId(manager));
   }
   public static int getId(Person person) {
      // check if person is employee then return employee id
      if (person instanceof Employee) {
         return ((Employee) person).getEmployeeId();
      }
      // if person is manager then return manager id
      else if (person instanceof Manager) {
         return ((Manager) person).getManagerId();
      }
      return -1;
   }
}

// a sealed class Person which is to be inherited by Employee
// and Manager classes
abstract sealed class Person permits Employee, Manager {
   String name;
   String getName() {
      return name;
   }
}

// Employee class has to extend Person and should have a modifier
final class Employee extends Person {
   String name;
   int id;
   Employee(int id, String name){
      this.id = id;
      this.name = name;
   }
   int getEmployeeId() {
      return id;
   }
}

// We can mark a sub-class as non-sealed, so that it can be extended if required
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