你知曉Java中的EnumMap嗎?

提到Java中集合Map,你可能常用的是HashMap/ConcurrentHashMap,但是當Map的key是列舉型別時,是否想過使用EnumMap了?

那麼當key是列舉型別時,EnumMap和HashMap的區別是啥?

HashMap:使用Hash表儲存,底層是陣列,陣列中存的是entry物件,預設長度是16。也就說每次向Map中加入物件,首先根據key值計算hash值,然後根據陣列長度放到合適的位置,當發生衝突時,使用“開鏈法”,即在衝突位置加入連結串列;Java8在解決衝突時,又新增了紅黑樹的解決方案。總體來說,HashMap就是空間換時間的方式來提高訪問效率。但是假如我們已知key的所有值時,是否還有必要每次都要計算hash值,然後找位置,解決衝突,甚者擴容了。。。

EnumMap:既然已知了所有key,那麼申請已知大小的陣列,每次訪問時根據列舉變數的ordinal值定位到陣列的指定位置,存取即可,這樣是不是既高效,且不會浪費儲存中間。

下面就進入EnumMap的內部探秘吧

主要成員:

public class EnumMap, V> extends AbstractMap implements java。io。Serializable, Cloneable { // key值的列舉型別 private final Class keyType; //根據key值的列舉型別,會預先快取所有的列舉變數 private transient K[] keyUniverse; /** * 所有的vlaue值,陣列的下標是列舉變數的序號(ordinal) * 陣列的內容是map中列舉變數對應的vlaue */ private transient Object[] vals; //當前map的大小, private transient int size = 0;}

使用詳解:

假設預先定了這樣的Enum物件

public enum WeekEnum { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;}

構造方法:

// 構造方法使用示例EnumMap weekEnumMap = new EnumMap<>(WeekEnum。class);// 會預先獲取所有的列舉值,然後根據列舉值的個數,建立相應大小的陣列用來存放valuepublic EnumMap(Class keyType) { this。keyType = keyType; keyUniverse = getKeyUniverse(keyType); vals = new Object[keyUniverse。length];}

put方法:

// 檢查列舉值型別,然後根據key的序號,將value存入相應下標的陣列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); }

get方法:

// 依然是先校驗key值型別,然後根據key的序號去陣列的位置取值public V get(Object key) { return (isValidKey(key) ? unmaskNull(vals[((Enum<?>)key)。ordinal()]) : null);}