Java 简明教程

Java - Sealed Classes and Interfaces

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

Java 15 introduced a sealed class as a preview feature which provides a fine-grained control over inheritance. Java 16 provides some minor enhancements and keeps this feature as a Preview. With Java 17, sealed class and interface a standard features. A sealed class/interface feature is added to Java to provide developers a fine fine-grained control over inheritance. A sealed class can define the subtypes that are permitted to extend it while other classes cannot extend it.

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

The following are salient points to consider for a sealed class −

  1. A sealed class is declared using a sealed keyword.

  2. Sealed classes allow to declaration of which class can be a subtype using the permits keyword.

  3. A class extending sealed class must be declared as either sealed, non-sealed, or final.

  4. Sealed classes help in creating a finite and determinable hierarchy of classes in inheritance.

Sealed Interface

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

An interface can be marked as sealed interface using sealed keyword and then using permits keywords, we can add the interfaces which can extend this interface.

public sealed interface Person permits Employee, Manager {
}

Sealed Interface Example

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

In this example, we’ve created a sealed interface Person which permits Employee and Manager interfaces to extend it. Employee and Manager interfaces have different methods to get the ID of a person. Now in order to get ID of a person, we’re using instanceof operator to check an instance being of Employee or Manager and get the corresponding ID. Thus we can see, that knowing the permissible interfaces upfront helps in development for such scenarios.

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;
   }
}

让我们编译并运行上述程序,这将生成以下结果 −

Let us compile and run the above program, this will produce the following result −

Id: 23

Sealed Class

类似于密封接口,可以使用 sealed 关键字将 class 标记为 sealed class,然后使用 permits 关键字,我们可以添加可以扩展此类的子类。

Similar to sealed interface, a class can be marked as sealed class as well using sealed keyword and then using permits keywords, we can add the subclasses which can extend this class.

public abstract sealed class Person permits Employee, Manager {
}

子类需要具有 sealed/final 或 non-sealed 修改符。

A subclass needs to have a modifier as sealed/final or non-sealed.

public final class Manager extends Person {
}

具有 non-sealed 的子类可以供所有类扩展。

A subclass with non-sealed is open for all classes to extend.

public non-sealed class Employee extends Person {
}

Constraints

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

There are few constraint on usage of sealed classes which we should notice while extending a sealed class.

  1. Permitted subclass should be part of same module as of sealed class.

  2. Permitted subclass has to extend the sealed class.

  3. A permitted subclass has to use any one of final, sealed, or non-sealed modifier.

Sealed Class Example

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

In this example, we’ve created a sealed abstract class Person which permits Employee and Manager classes to extend it. Employee and Manager classes have different methods to get the ID of a person. Now in order to get ID of a person, we’re using instanceof operator to check an instance being of Employee or Manager and get the corresponding ID. Thus we can see, that knowing the permissible SubClasses upfront helps in development for such scenarios.

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;
   }
}

让我们编译并运行上述程序,这将生成以下结果 −

Let us compile and run the above program, this will produce the following result −

Id: 23