第33條:用EnumMap代替序數(shù)索引

序數(shù)索引是指依賴于枚舉成員在枚舉中的序數(shù)(ordinal方法返回值)來進行數(shù)組索引,如:
public class Herb {
public enum Type {
ANNUAL, PERENNTAL, BIENNIAL
}

private final String name;
private final Type type;

Herb(String name, Type type) {
    this.name = name;
    this.type = type;
}

@Override
public String toString() {
    return name;
}
public static void main(String[] args) {
 // 將集合放到一個按照類型的序數(shù)進行索引的數(shù)組中來實現(xiàn)  替換
    Herb[] garden = {new Herb("一年生1", Type.ANNUAL), new Herb("一年生2", Type.ANNUAL), 
            new Herb("兩年生1", Type.BIENNIAL), new Herb("兩年生2", Type.BIENNIAL),
            new Herb("多年生1", Type.PERENNTAL), new Herb("多年生2", Type.PERENNTAL)};

    Set<Herb>[] herbsByType = (Set<Herb>[])new Set[Herb.Type.values().length];
    for(int i = 0;i<herbsByType.length;i++){
        herbsByType[i] = new HashSet<Herb>();
    }
    for(Herb h:garden){
        herbsByType[h.type.ordinal()].add(h);
    } 
    for (int i = 0; i < herbsByType.length; i++) {
        System.out.printf("%s: %s%n", Herb.Type.values(), herbsByType[i]);
    }
}

}
  結果:
    [Ltest.Herb$Type;@76e704e1: [一年生1, 一年生2]
    [Ltest.Herb$Type;@7a507369: [多年生2, 多年生1]
    [Ltest.Herb$Type;@37c9313b: [兩年生1, 兩年生2]
  這種方法的確可行,但是隱藏著許多問題。因為數(shù)組不能與泛型兼容。程序需要進行未受檢的轉(zhuǎn)換,并且不能正確無誤地進行編譯。因為數(shù)組不知道它的索引代表著什么,你必須手工標注這些索引的輸出。但是這種方法最嚴重的問題在于,當你訪問一個按照枚舉的序數(shù)進行索引的數(shù)組時,使用正確的int值就是你的職責了;int不能提供枚舉的類型安全。你如果使用了錯誤的值,程序就會悄然地完成錯誤的工作,或者幸運的話就會拋出ArrayIndexOutOfBoundException異常。
  對于上述問題,java.util.EnumMap是一種非??焖俚腗ap實現(xiàn)專門用于枚舉的鍵。修改后:

        Herb[] garden = {new Herb("一年生1", Type.ANNUAL), new Herb("一年生2", Type.ANNUAL), 
                new Herb("兩年生1", Type.BIENNIAL), new Herb("兩年生2", Type.BIENNIAL),
                new Herb("多年生1", Type.PERENNTAL), new Herb("多年生2", Type.PERENNTAL)};
        Map<Herb.Type, Set<Herb>> herbsByType = new EnumMap<Herb.Type,Set<Herb>>(Herb.Type.class);
        for(Herb.Type t:Herb.Type.values()){
            herbsByType.put(t, new HashSet<Herb>());
        }
        for(Herb h:garden){
            herbsByType.get(h.type).add(h); 
        }
        System.out.println(herbsByType);
    }```
  結果:{ANNUAL=[一年生1, 一年生2], PERENNTAL=[多年生1, 多年生2], BIENNIAL=[兩年生1, 兩年生2]}

  這段程序更簡短,更清楚,也更安全,運行速度方面可以與使用序數(shù)的程序相媲美。它沒有不安全的轉(zhuǎn)換;不必手工標注出這些索引的輸出,因為映射鍵知道如何將自身翻譯成可打印的字符串的枚舉;計算數(shù)組索引時也不可能出錯。EnumMap在運行速度方面之所以能與通過序數(shù)索引的數(shù)組相媲美,是因為EnumMap在內(nèi)部使用了這種數(shù)組。但是它對程序員隱藏了這種思想細節(jié),集Map的豐富功能和類型安全與數(shù)組的快速于一身。注意EnumMap構造器采用鍵類型的Class對象:這是一個有限制的類型令牌(bounded type token),它提供了運行時的泛型信息。
附EnumMap的put和get方法
```public V put(K key, V value) {
        typeCheck(key);
        int index = key.ordinal();
        Object oldValue = vals[index];
        vals[index] = maskNull(value);
        if (oldValue == null)
            size++;
        return unmaskNull(oldValue);
    }
public V get(Object key) {
        return (isValidKey(key) ?
                unmaskNull(vals[((Enum)key).ordinal()]) : null);
    }```
  以上描述的為一維的關系,如果表示這種關系是多維的,那么就是用EnumMap<..., EnumMap<...>>來實現(xiàn),應用程序程序員在一般情況下都不使用Enum.ordinal,即使要用也很少,因此這是一種特殊情況。
總結:
  ***最好不要使用序數(shù)來索引數(shù)組,而是使用EnumMap。***
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • EnumMap定義 1 以java7進行說明 2 成員屬性說明1)EnumMap的鍵是繼承Enum類型的對象2)成...
    paulpaullong閱讀 367評論 0 1
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內(nèi)部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,734評論 18 399
  • 對象的創(chuàng)建與銷毀 Item 1: 使用static工廠方法,而不是構造函數(shù)創(chuàng)建對象:僅僅是創(chuàng)建對象的方法,并非Fa...
    孫小磊閱讀 2,184評論 0 3
  • 一、基本數(shù)據(jù)類型 注釋 單行注釋:// 區(qū)域注釋:/* */ 文檔注釋:/** */ 數(shù)值 對于byte類型而言...
    龍貓小爺閱讀 4,455評論 0 16
  • 一陣風 帶著小小只的蒲公英 來到這方土地 掬一勺清水 滿滿的 寄思緒于秋葉 行囊里的白襯衫 是無法回頭的旅行 期待...
    Lavender蘇閱讀 325評論 0 2

友情鏈接更多精彩內(nèi)容