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

JDK 5.0 枚舉類型完全掌握:從基礎到進階實戰

     編輯:Java 程式設計入門

JDK 5.0 引入 enum 關鍵字,將枚舉從「整數常量模式」提升為功能完整的類。枚舉實例是單例、天然線程安全、可實現接口、可定義方法/字段/構造器。本文系統梳理枚舉七大特性、進階用法、設計模式應用及最佳實踐。

枚舉七大核心特性

特性說明代碼驗證
無 public 構造器編譯器強制 private,保證實例受控new Color() → 編譯錯誤
實例為單例public static final,JVM 保證唯一Color.RED == Color.RED → true
實現 Comparable按聲明順序比較,ordinal() 返回索引Color.RED.compareTo(Color.BLUE) < 0
覆寫 toString()默認返回常量名,可自定義Color.RED.toString() → "RED"
valueOf() 反向解析Color.valueOf("RED") → Color.RED,大小寫敏感異常處理:IllegalArgumentException
values() 遍歷返回聲明順序數組,for (Color c : Color.values())編譯器生成靜態方法
ordinal() 索引從 0 開始,慎用於業務邏輯(插入枚舉值會改變索引)Color.RED.ordinal() == 0

基礎定義與遍歷

public enum Color {
    RED, GREEN, BLUE;
    
    // 遍歷演示
    public static void printAll() {
        for (Color c : Color.values()) {
            System.out.println(c + " ordinal=" + c.ordinal());
        }
    }
}

進階:字段、方法、構造器

public enum Color {
    RED("紅色", 0xFF0000),
    GREEN("綠色", 0x00FF00),
    BLUE("藍色", 0x0000FF);
    
    private final String chineseName;
    private final int rgb;
    
    // 私有構造器,枚舉值聲明處調用
    Color(String chineseName, int rgb) {
        this.chineseName = chineseName;
        this.rgb = rgb;
    }
    
    public String getChineseName() { return chineseName; }
    public int getRGB() { return rgb; }
    
    // 靜態工廠:隨機顏色
    private static final Random RANDOM = new Random();
    public static Color randomColor() {
        return values()[RANDOM.nextInt(values().length)];
    }
    
    // 覆寫 toString
    @Override public String toString() {
        return name() + "(" + chineseName + ")";
    }
}

關鍵規則:字段/方法/構造器必須寫在枚舉值列表之後,且構造器只能 private 或包私有。

覆寫 toString() 與 valueOf() 一致性

public enum Status {
    SUCCESS("操作成功"), FAILURE("操作失敗");
    
    private final String desc;
    Status(String desc) { this.desc = desc; }
    
    @Override public String toString() { return desc; }
    
    // 必須同步覆寫 valueOf 邏輯(實際需配合映射表)
    public static Status fromDescription(String desc) {
        for (Status s : values()) {
            if (s.desc.equals(desc)) return s;
        }
        throw new IllegalArgumentException("Unknown desc: " + desc);
    }
}

枚舉實現接口:策略模式最佳載體

public interface DiscountStrategy {
    BigDecimal apply(BigDecimal original);
}

public enum Discount implements DiscountStrategy {
    NONE("無折扣") {
        @Override public BigDecimal apply(BigDecimal original) { return original; }
    },
    VIP_10("VIP 9折") {
        @Override public BigDecimal apply(BigDecimal original) { 
            return original.multiply(new BigDecimal("0.9")); 
        }
    },
    HOLIDAY_20("節日 8折") {
        @Override public BigDecimal apply(BigDecimal original) { 
            return original.multiply(new BigDecimal("0.8")); 
        }
    };
    
    private final String desc;
    Discount(String desc) { this.desc = desc; }
    public String getDesc() { return desc; }
}

// 使用
BigDecimal price = new BigDecimal("100");
Discount.VIP_10.apply(price); // 90.0
Discount.HOLIDAY_20.apply(price); // 80.0

枚舉實現狀態機:類型安全狀態轉換

public enum OrderState {
    PENDING {
        @Override public OrderState next() { return PAID; }
        @Override public boolean canCancel() { return true; }
    },
    PAID {
        @Override public OrderState next() { return SHIPPED; }
        @Override public boolean canCancel() { return false; }
    },
    SHIPPED {
        @Override public OrderState next() { return DELIVERED; }
        @Override public boolean canCancel() { return false; }
    },
    DELIVERED {
        @Override public OrderState next() { throw new IllegalStateException("已送達"); }
        @Override public boolean canCancel() { return false; }
    };
    
    public abstract OrderState next();
    public abstract boolean canCancel();
}

// 使用
OrderState state = OrderState.PENDING;
state = state.next(); // PAID
state.canCancel(); // false

EnumMap / EnumSet:專用高性能集合

// EnumMap:鍵為枚舉,數組底層,極快
EnumMap colorNames = new EnumMap<>(Color.class);
colorNames.put(Color.RED, "紅");
colorNames.put(Color.GREEN, "綠");

// EnumSet:位向量底層,極省內存、極快
EnumSet primaryColors = EnumSet.of(Color.RED, Color.GREEN, Color.BLUE);
EnumSet allColors = EnumSet.allOf(Color.class);
EnumSet complement = EnumSet.complementOf(primaryColors); // 空集

最佳實踐清單

  1. 替代 int/String 常量:類型安全、自帶命名空間、IDE 智能提示
  2. 實現單例模式:public enum Singleton { INSTANCE; } — 防反射/序列化破壞,Effective Java 推薦
  3. 策略/狀態/命令模式:枚舉實現接口,每個實例一種行為變體
  4. 慎用 ordinal():業務邏輯勿依賴聲明順序,改用顯式字段
  5. 序列化安全:枚舉序列化只寫常量名,反序列化調用 valueOf(),天然防偽造
  6. switch 表達式:Java 12+ switch (color) { case RED -> ... } 編譯器檢查完整性

常見誤區

誤區正確認知
枚舉不能有方法可定義實例/靜態方法、字段、構造器、實現接口
枚舉值可修改枚舉實例不可變,字段必須 final
values() 返回可修改數組返回副本,修改不影響原枚舉
可繼承枚舉枚舉隱含 final,不可繼承(但可實現接口)

枚舉是 Java 類型系統的「瑞士軍刀」——小巧、強大、類型安全。善用之,代碼更清晰、Bug 更少。

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