自 Java 5 引入 enum 關鍵字以來,枚舉類型已成為表達「固定常量集合」的首選方案。它不僅提供型別安全,還具備豐富的物件導向特性。本文將系統梳理枚舉的核心特點、遍歷方式、常用方法、建構子用法,並以「交通燈狀態機」為例展示實戰應用。
java.lang.Enum使用 enum 定義的類別,預設繼承 java.lang.Enum 而非 Object。Enum 類別實作了 Serializable 與 Comparable 介面,因此枚舉實例天生可序列化、可比較。
private枚舉的建構子只能是 private(省略修飾符時預設為 private),這保證了外部無法透過 new 建立新實例,確保實例數量固定。
所有實例必須在枚舉定義的開頭以逗號分隔列出,結尾以分號結束。系統會自動為每個實例添加 public static final 修飾符。
public enum Week {
MON {
public String toLocaleString() { return "星期一"; }
},
TUE {
public String toLocaleString() { return "星期二"; }
},
WED {
public String toLocaleString() { return "星期三"; }
},
THU {
public String toLocaleString() { return "星期四"; }
},
FRI {
public String toLocaleString() { return "星期五"; }
},
SAT {
public String toLocaleString() { return "星期六"; }
},
SUN {
public String toLocaleString() { return "星期日"; }
};
// 定義抽象方法,強制每個實例實作
public abstract String toLocaleString();
}
透過 values() 靜態方法獲取所有實例陣列,配合增強型 for 迴圈遍歷:
public class EnumTest {
public static void main(String[] args) {
for (Week w : Week.values()) {
System.out.println(w); // 輸出:MON, TUE, ...
}
}
}
| 方法 | 說明 |
|---|---|
int compareTo(E o) | 比較兩個枚舉常數的宣告順序 |
String name() | 返回枚舉常數的名稱(如 "MON") |
int ordinal() | 返回枚舉常數的索引(從 0 開始) |
String toString() | 返回常數名稱,可覆寫以提供更友善輸出 |
static <T> T valueOf(String name) | 根據名稱字串返回對應的枚舉常數 |
values() | 返回包含所有枚舉常數的陣列 |
public class EnumTest {
public static void main(String[] args) {
Week day = Week.FRI;
System.out.println(day); // FRI
System.out.println(day.name()); // FRI
System.out.println(day.ordinal()); // 4
System.out.println(Week.valueOf("SUN").toLocaleString()); // 星期日
System.out.println(Week.values().length); // 7
}
}
枚舉可擁有屬性、建構子與方法,實現豐富的行為:
public enum Gender {
MALE("男"), FEMALE("女");
private final String name;
private Gender(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return name;
}
}
利用枚舉的「單例特性」與「可攜帶行為」特點,優雅實現交通燈狀態轉換邏輯:

public enum Lamp {
// 主幹道直行燈(帶有對向燈、下一燈、初始亮滅狀態)
S2N("N2S", "S2W", false),
S2W("N2E", "E2W", false),
E2W("W2E", "E2S", false),
E2S("W2N", "S2N", false),
// 相反方向燈(不參與循環,僅作對向參考)
N2S(null, null, false),
N2E(null, null, false),
W2E(null, null, false),
W2N(null, null, false),
// 右轉燈(假想永遠綠燈)
S2E(null, null, true),
E2N(null, null, true),
N2W(null, null, true),
W2S(null, null, true);
private final String opposite; // 對向燈名稱
private final String next; // 下一個綠燈名稱
private boolean lighted; // 當前是否為綠燈
private Lamp(String opposite, String next, boolean lighted) {
this.opposite = opposite;
this.next = next;
this.lighted = lighted;
}
public boolean isLighted() { return lighted; }
// 變綠:自身與對向燈同時變綠
public void light() {
this.lighted = true;
if (opposite != null) Lamp.valueOf(opposite).light();
System.out.println(name() + " lamp is green");
}
// 變紅:自身與對向燈變紅,觸發下一燈變綠
public Lamp blackOut() {
this.lighted = false;
if (opposite != null) Lamp.valueOf(opposite).blackOut();
Lamp nextLamp = null;
if (next != null) {
nextLamp = Lamp.valueOf(next);
System.out.println("綠燈從 " + name() + " 切換為 " + next);
nextLamp.light();
}
return nextLamp;
}
}
if-else 或 switchJava 枚舉遠不止「常量集合」,它是功能完整的類別,支援屬性、方法、介面實作與多型。善用枚舉能讓代碼更具型別安全、可讀性與擴展性。下次面對「固定數量的業務狀態」時,請優先考慮 enum。