首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 枚舉類型全方位深度指南:從基礎用法到高級模式實戰

     編輯:Java 程式設計入門

枚舉基礎特性

  • 所有枚舉隱式繼承 java.lang.Enum
  • 實例為單例,JVM 保證線程安全創建
  • 編譯器自動添加 values()、valueOf(String) 靜態方法
  • final 類,不可被繼承
  • 可實現接口,支持多態

核心 API 演示


enum Shrubbery { GROUND, CRAWLING, HANGING }

for (Shrubbery s : Shrubbery.values()) {
    System.out.println(s + " ordinal: " + s.ordinal());
    System.out.println(s.compareTo(Shrubbery.CRAWLING));
    System.out.println(s == Shrubbery.CRAWLING);  // 枚舉比較用 == 安全
    System.out.println(s.getDeclaringClass());
    System.out.println(s.name());
}

// 字符串轉枚舉
Shrubbery s = Enum.valueOf(Shrubbery.class, "HANGING");

靜態導入與方法增強


// 靜態導入簡化調用
import static enumerated.Spiciness.*;
public class Burrito {
    Spiciness degree;
    public Burrito(Spiciness degree) { this.degree = degree; }
}

// 向枚舉添加方法、構造器、字段
public enum OzWitch {
    WEST("Miss Gulch"), NORTH("Glinda"), EAST("Wicked"), SOUTH("Good");
    private final String description;
    private OzWitch(String desc) { this.description = desc; }
    public String getDescription() { return description; }
    public static void main(String[] args) {
        for (OzWitch w : values()) 
            System.out.println(w + ": " + w.getDescription());
    }
}

// 覆寫 toString()
public enum SpaceShip {
    SCOUT, CARGO, BATTLESHIP;
    public String toString() {
        String id = name();
        return id.charAt(0) + id.substring(1).toLowerCase();
    }
}

Switch 語句中的枚舉


enum Signal { GREEN, YELLOW, RED }

public class TrafficLight {
    Signal color = Signal.RED;
    public void change() {
        switch (color) {
            case RED: color = Signal.GREEN; break;
            case GREEN: color = Signal.YELLOW; break;
            case YELLOW: color = Signal.RED; break;
        }
    }
}

case 標簽直接使用枚舉常量名,無需前綴類名。

values() 與 valueOf() 的編譯器魔法

  • values():編譯器生成的靜態方法,返回聲明順序數組
  • valueOf(String):編譯器生成單參數版本;Enum.valueOf(Class, String) 為雙參數基礎版本
  • 向上轉型為 Enum 後 values() 不可用,改用 Class.getEnumConstants()

實現而非繼承:接口組織枚舉


// 接口內嵌套枚舉分組
public interface Food {
    enum Appetizer implements Food { SALAD, SOUP }
    enum MainCourse implements Food { LASAGNE, BURRITO }
    enum Dessert implements Food { TIRAMISU, GELATO }
}

// 統一類型引用
Food food = Appetizer.SALAD;
food = MainCourse.LASAGNE;

// 枚舉封裝枚舉:隨機選餐
public enum Course {
    APPETIZER(Food.Appetizer.class), MAIN_COURSE(Food.MainCourse.class);
    private final Food[] values;
    Course(Class clazz) { values = clazz.getEnumConstants(); }
    public Food randomSelection() { return Enums.random(values); }
}

EnumSet:替代位標志的高性能集合


enum AlarmPoints { STAIR1, STAIR2, LOBBY, OFFICE1, KITCHEN }

EnumSet set = EnumSet.noneOf(AlarmPoints.class);
set.add(STAIR1);
set.addAll(EnumSet.of(LOBBY, KITCHEN));
set.removeAll(EnumSet.range(OFFICE1, OFFICE4));
EnumSet complement = EnumSet.complementOf(set);

// 內部用 long 位向量,64位以內單 long,超過自動擴展為 long[]
// 性能遠優於 HashSet,類型安全

EnumMap:枚舉鍵的極致性能 Map


EnumMap map = new EnumMap<>(AlarmPoints.class);
map.put(KITCHEN, () -> System.out.println("Kitchen fire!"));
map.put(BATHROOM, () -> System.out.println("Bathroom alert!"));

for (Map.Entry e : map.entrySet()) {
    e.getValue().action();
}
// 內部用數組實現,O(1) 訪問,無哈希計算、無裝箱

常量特定方法體:每個實例不同行為


public enum ConstantSpecificMethod {
    DATE_TIME { String getInfo() { return new Date().toString(); } },
    CLASSPATH { String getInfo() { return System.getenv("CLASSPATH"); } },
    VERSION { String getInfo() { return System.getProperty("java.version"); } };
    abstract String getInfo();
}

// 等價於為每個常量創建匿名內部類繼承枚舉基類
// 但枚舉常量不是獨立類型,不能作參數類型

責任鏈模式:郵件處理實戰


enum MailHandler {
    GENERAL_DELIVERY { boolean handle(Mail m) { ... } },
    MACHINE_SCAN { boolean handle(Mail m) { ... } },
    VISUAL_INSPECTION { boolean handle(Mail m) { ... } },
    RETURN_TO_SENDER { boolean handle(Mail m) { ... } };
    abstract boolean handle(Mail m);
}

static void handle(Mail m) {
    for (MailHandler h : MailHandler.values())
        if (h.handle(m)) return;
    System.out.println(m + " is dead letter");
}

狀態機實現:自動售貨機


enum Input { NICKEL(5), DIME(10), QUARTER(25), DOLLAR(100), 
    TOOTHPASTE(200), CHIPS(75), SODA(100), SOAP(50),
    ABORT_TRANSACTION, STOP;  // 無金額特殊輸入
    int value;
    Input(int v) { value = v; }
    Input() {}
    int amount() { return value; }
}

enum Category {
    MONEY(NICKEL, DIME, QUARTER, DOLLAR),
    ITEM_SELECTION(TOOTHPASTE, CHIPS, SODA, SOAP);
    private final Input[] values;
    Category(Input... v) { values = v; }
    private static final EnumMap MAP = new EnumMap<>(Input.class);
    static { for (Category c : values()) for (Input i : c.values) MAP.put(i, c); }
    public static Category categorize(Input i) { return MAP.get(i); }
}

enum State {
    RESTING { void next(Input i) { switch(Category.categorize(i)) { case MONEY: amount+=i.amount(); state=ADDING_MONEY; break; ... } } },
    ADDING_MONEY { void next(Input i) { ... } },
    DISPENSING(TRANSIENT) { void next() { ... } },
    GIVING_CHANGE(TRANSIENT) { void next() { ... } },
    TERMINAL { void output() { System.out.println("Halted"); } };
    boolean isTransient = false;
    State() {}
    State(StateDuration d) { isTransient = true; }
    abstract void next(Input i);
    abstract void next();
    void output() { System.out.println(amount); }
}

多重分派解決方案:剪刀石頭布

方案 1:查找表


enum RoShamBo5 implements Competitor {
    PAPER, SCISSORS, ROCK;
    static final EnumMap> TABLE = new EnumMap<>(RoShamBo5.class);
    static {
        for (RoShamBo5 r : values()) TABLE.put(r, new EnumMap<>(RoShamBo5.class));
        initRow(PAPER, DRAW, LOSE, WIN);
        initRow(SCISSORS, WIN, DRAW, LOSE);
        initRow(ROCK, LOSE, WIN, DRAW);
    }
    static void initRow(RoShamBo5 r, Outcome... o) {
        EnumMap row = TABLE.get(r);
        row.put(PAPER, o[0]); row.put(SCISSORS, o[1]); row.put(ROCK, o[2]);
    }
    public Outcome compete(RoShamBo5 other) { return TABLE.get(this).get(other); }
}

方案 2:二維數組(最簡潔)


enum RoShamBo6 implements Competitor {
    PAPER, SCISSORS, ROCK;
    private static final Outcome[][] TABLE = {
        { DRAW, LOSE, WIN },   // PAPER
        { WIN, DRAW, LOSE },   // SCISSORS
        { LOSE, WIN, DRAW }    // ROCK
    };
    public Outcome compete(RoShamBo6 other) { return TABLE[ordinal()][other.ordinal()]; }
}

核心洞見:枚舉實例固定、有序、可作數組索引,使查找表/矩陣成為多重分派的高性能實現。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved