Java 教程

Java 控制語句

面向物件程式設計

Java 內建類

Java 檔案處理

Java 錯誤和異常

Java 多執行緒

Java 同步

Java 網路

Java 集合

Java 介面

Java 資料結構

Java 集合演算法

高階 Java

Java 雜項

Java API 和框架

Java 類引用

Java 有用資源

Java - 密封類和介面



Java 15 引入了一個密封類作為預覽功能,它提供了對繼承的細粒度控制。Java 16 提供了一些小的增強功能,並將此功能保留為預覽。隨著 Java 17 的釋出,密封類和介面成為了標準特性。密封類/介面功能新增到 Java 中,為開發人員提供了對繼承的細粒度控制。密封類可以定義允許擴充套件它的子型別,而其他類則不能擴充套件它。

以下是需要考慮的密封類的要點:

  • 密封類使用 sealed 關鍵字宣告。
  • 密封類允許使用 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) {
      // 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關鍵字標記為密封類,然後使用 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) {
      // 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
廣告