Java 5 引入 enum 類型,不僅是常數集合,更是功能完整的類別,支援欄位、方法、介面實作、匿名內部類別覆寫。本文以紅綠燈狀態機為例,全面解析 Enum 進階特性與設計模式應用。
public class TrafficLightDemo {
public static void main(String[] args) {
TrafficLight light = TrafficLight.RED;
System.out.println("當前狀態: " + light); // RED
System.out.println("持續時間: " + light.getTime()); // 30
System.out.println("下一狀態: " + light.nextLight()); // YELLOW
System.out.println("宣告順序: " + light.ordinal()); // 1
// 遍歷所有列舉值
System.out.println("所有狀態:");
for (TrafficLight l : TrafficLight.values()) {
System.out.println(" " + l.name() + " (ordinal=" + l.ordinal() + ")");
}
// 字串轉列舉 (大小寫敏感)
System.out.println("RED == valueOf(\"RED\"): " + (TrafficLight.RED == TrafficLight.valueOf("RED"))); // true
}
}
enum TrafficLight {
// 每個列舉常數是 TrafficLight 的匿名子類別實例
GREEN(30) {
@Override public TrafficLight nextLight() { return RED; }
},
RED(30) {
@Override public TrafficLight nextLight() { return YELLOW; }
},
YELLOW(10) {
@Override public TrafficLight nextLight() { return GREEN; }
};
// 抽象方法強制各常數實作
public abstract TrafficLight nextLight();
// 共享欄位與建構子
private final int time;
private TrafficLight(int time) { this.time = time; }
public int getTime() { return time; }
}
| 特性 | 說明 | 範例 |
|---|---|---|
| 類別本質 | 隱含 final、繼承 java.lang.Enum、不可再繼承 | enum E {} → class E extends Enum<E> |
| 常數實例 | 每個常數是唯一實例,JVM 保證單例 | TrafficLight.RED == TrafficLight.RED (true) |
| 建構子 | 只能 private,常數宣告時呼叫 | RED(30) 呼叫 private TrafficLight(int) |
| 匿名子類別 | 大括號內可覆寫方法,每個常數可有不同行為 | GREEN { nextLight() { return RED; } } |
| 介面實作 | 可實作介面,每個常數可不同實作 | enum E implements I { A { m(){} }, B { m(){} } } |
| 靜態導入 | import static pkg.E.*; 直接使用 A, B |
TrafficLight[] all = TrafficLight.values(); // 所有常數陣列 (依宣告順序)
TrafficLight red = TrafficLight.valueOf("RED"); // 字串轉常數 (不存在拋 IllegalArgumentException)
String name = TrafficLight.RED.name(); // "RED" (不可覆寫)
int ordinal = TrafficLight.RED.ordinal(); // 0-based 宣告索引
Class<TrafficLight> clazz = TrafficLight.RED.getDeclaringClass(); // 列舉類別 Class
int compare = TrafficLight.RED.compareTo(TrafficLight.GREEN); // 比較 ordinal
// EnumSet: 位元向量實作,極度高效
Set active = EnumSet.of(TrafficLight.RED, TrafficLight.GREEN);
Set all = EnumSet.allOf(TrafficLight.class);
Set range = EnumSet.range(TrafficLight.RED, TrafficLight.YELLOW);
// EnumMap: 陣列實作,鍵為 Enum 時比 HashMap 快數倍
Map desc = new EnumMap<>(TrafficLight.class);
desc.put(TrafficLight.RED, "停止");
desc.put(TrafficLight.GREEN, "通行");
enum PayStrategy {
ALIPAY { public void pay(double amt) { System.out.println("支付寶付款: " + amt); }},
WECHAT { public void pay(double amt) { System.out.println("微信付款: " + amt); }},
CREDIT_CARD { public void pay(double amt) { System.out.println("信用卡付款: " + amt); }};
public abstract void pay(double amount);
}
// 使用
PayStrategy.ALIPAY.pay(100.0);
enum OrderState {
PENDING {
@Override public OrderState next() { return PAID; }
@Override public void handle(Order ctx) { ctx.setPaidTime(now()); }
},
PAID {
@Override public OrderState next() { return SHIPPED; }
@Override public void handle(Order ctx) { ctx.setShipTime(now()); }
},
SHIPPED { @Override public OrderState next() { return DONE; }},
DONE { @Override public OrderState next() { return this; }};
public abstract OrderState next();
public abstract void handle(Order ctx);
}
enum Singleton {
INSTANCE;
private Resource resource;
public Resource getResource() { return resource; }
}
// 使用: Singleton.INSTANCE.getResource()
valueOf 還原serialVersionUID、transient、readObject/writeObject 影響Enum 是 Java 型別系統威力的展現:型別安全、行為封裝、高效能集合、設計模式原生支援,善用之可大幅提升代碼品質。