Java 中的 枚舉(Enum) 是一種特殊的類,用于表示一組固定且有限的常量(如狀態、類型、選項等)。它提供類型安全的常量定義,比傳統的常量(如 public static final
)更強大和靈活。以下是 Java 枚舉的詳細講解:
一、枚舉的基本語法
public enum Season {SPRING, SUMMER, AUTUMN, WINTER; // 常量必須放在最前面
}
底層實現:
- 枚舉本質是繼承自
java.lang.Enum
的類,每個枚舉常量都是該類的實例(單例)。 - 編譯器會自動生成
values()
和valueOf(String)
方法。
二、枚舉的核心特性
1. 類型安全
- 枚舉常量是類型明確的,不能隨意賦值其他類型。
Season currentSeason = Season.SPRING; // 只能賦值 Season 的常量
2. 固定常量集合
- 枚舉的常量在定義時確定,無法運行時動態修改。
3. 可附加屬性和方法
- 枚舉可以定義字段、構造函數和方法,實現更復雜的邏輯:
public enum Planet {MERCURY(3.303e+23, 2.4397e6),VENUS(4.869e+24, 6.0518e6);private final double mass; // 屬性private final double radius; Planet(double mass, double radius) { // 構造函數(默認 private)this.mass = mass;this.radius = radius;}public double surfaceGravity() { // 方法return mass / (radius * radius);}
}
4. 可實現接口
- 枚舉可以實現接口,但無法繼承其他類(因為已經隱式繼承
Enum
)。
public interface Printable {void print();
}public enum Color implements Printable {RED {public void print() { System.out.println("紅色"); }},GREEN {public void print() { System.out.println("綠色"); }};
}
三、枚舉的常用方法
1. 內置方法
values()
:返回枚舉所有常量的數組。valueOf(String name)
:根據名稱返回對應的枚舉常量。name()
:返回枚舉常量的名稱(字符串形式)。ordinal()
:返回枚舉常量的聲明順序(從 0 開始)。
2. 示例代碼
Season[] seasons = Season.values(); // 獲取所有枚舉值
Season s = Season.valueOf("SPRING"); // 根據名稱獲取枚舉
System.out.println(s.name()); // 輸出 "SPRING"
System.out.println(s.ordinal()); // 輸出 0
四、枚舉的高級用法
1. 枚舉與單例模式
- 枚舉是實現線程安全單例的最佳方式(防止反射攻擊和序列化問題):
public enum Singleton {INSTANCE;public void doSomething() {// 業務邏輯}
}
2. 枚舉作為狀態機
- 通過枚舉的屬性和方法,可以優雅地實現狀態流轉:
public enum OrderStatus {NEW {public OrderStatus next() { return PAID; }},PAID {public OrderStatus next() { return SHIPPED; }},SHIPPED {public OrderStatus next() { return COMPLETED; }},COMPLETED {public OrderStatus next() { return this; }};public abstract OrderStatus next();
}
3. 策略模式
- 通過枚舉實現不同的策略行為:
public enum Operation {ADD { public int apply(int a, int b) { return a + b; } },SUB { public int apply(int a, int b) { return a - b; } };public abstract int apply(int a, int b);
}
五、枚舉的注意事項
-
構造函數私有化
枚舉的構造函數默認是private
,不能手動修改為public
或protected
。 -
常量定義位置
枚舉常量必須定義在類的第一行,之后才能定義字段和方法。 -
性能與內存
枚舉比常量占用更多內存(每個常量是一個對象實例),但在大多數場景下影響可忽略。 -
序列化
枚舉的序列化僅存儲名稱,反序列化時通過valueOf
恢復,天然安全。
六、枚舉 vs 常量類
特性 | 枚舉 | 常量類(public static final) |
---|---|---|
類型安全 | ?? 編譯時檢查類型 | ? 只是 int/String 常量 |
可附加方法 | ?? 支持方法和屬性 | ? 只能定義簡單值 |
擴展性 | ? 常量固定 | ?? 可隨意添加新常量(但破壞封裝) |
線程安全 | ?? 實例天然單例且不可變 | ? 需手動控制 |
七、總結
使用枚舉的場景:
- 需要一組固定的、類型安全的常量(如狀態、錯誤碼、配置選項)。
- 需要為常量附加行為或數據(如計算、狀態流轉)。
- 實現單例或策略模式。
避免枚舉的場景:
- 需要動態生成常量(如從數據庫加載)。
- 對內存極度敏感(如嵌入式開發)。
枚舉是 Java 中一種強大的工具,合理使用可以大幅提升代碼的可讀性和健壯性。