Java 列舉與介面

最後更新: 2024-06-05 02:14:10 +0800 +0800
tags: Enums | Java
原文以英文撰寫。您正在閱讀AI翻譯版本。

列舉宣告會定義一個具有固定實例集合的最終類別。每個常數都是該類別的實例;概念上,它會以列舉型別作為 E,擴充 Enum<E>;任何使用者列舉都不能再擴充其他類別。編譯器會提供 values() 與 valueOf(String),而 Enum 會提供名稱、序數、比較與序列化規則。

介面與常數特定行為 #

列舉可以實作介面,而實作可以由所有常數共用,或由常數特定的類別主體提供。

java
enum Operation {
    ADD { int apply(int a, int b) { return a + b; } },
    SUBTRACT { int apply(int a, int b) { return a - b; } };

    abstract int apply(int a, int b);
}

每個常數特定的主體都是編譯器產生的匿名子類別。因此,虛擬分派會選取其覆寫版本。外圍列舉仍是封閉集合,所以當策略在編譯時期已知時,這是有效的策略實作。當擴充功能必須獨立安裝時,優先使用注入的介面實作。

常數特定的主體可以實作抽象列舉方法。當行為共用時,適合使用列舉層級的實作。除非其生命週期刻意設計為涵蓋整個程序,否則不要在列舉常數中保留可變狀態:列舉實例會由其定義類別載入器初始化一次。

身分、順序與集合 #

列舉序列化會保留單例身分:反序列化會依名稱解析常數,而不是配置新的實例。clone 被禁止,且禁止透過反射建立列舉實例。使用 == 比較列舉身分,並避免持久化 ordinal(),因為插入或重新排列常數會改變它。只有在明確承諾原始碼層級的穩定性時,才持久化 name();對長期資料而言,外部程式碼欄位更安全。

Enum.compareTo 會依宣告順序排列常數。EnumSet 使用常數序數緊密表示集合,而 EnumMap 依列舉鍵索引值。兩者都要求單一列舉型別;當這項限制符合需求時,優先使用它們,而非通用集合。

java
EnumSet<Operation> enabled = EnumSet.of(Operation.ADD);
EnumMap<Operation, String> labels = new EnumMap<>(Operation.class);
labels.put(Operation.ADD, "addition");

參考資料 #

評論

在 GitHub 上閱讀或評論(發表評論需要登入)