EnumMap 原理相關(guān)

問:簡單談?wù)勀銓?EnumMap 的理解及其特點與應(yīng)用場景?

答:EnumMap 是對 Map 接口的實現(xiàn)類,其 key-value 映射中的 key 是 Enum 類型,其原理是一個對象數(shù)組,數(shù)組的下標(biāo)索引就是根據(jù) Map 中的 key 直接獲取(即枚舉中的 ordinal 值),數(shù)組長度就是枚舉類成員個數(shù);當(dāng) key 為枚舉類型時其效率比 HashMap 高,因為可以直接獲取數(shù)組下標(biāo)索引訪問到元素;此外 EnumMap 是保證順序的,輸出是按照 key 在枚舉中的順序來確定的。

大多數(shù)時候使用 EnumMap 的場景都是 key-value 對存儲中 key 為枚舉類型的場景,不過需要注意 EnumMap 的構(gòu)造方法,如下:

//需要傳遞一個類型信息,因為沒有這個類信息就不知道具體的枚舉類是什么,
// 也就無法初始化內(nèi)部的數(shù)據(jù)結(jié)構(gòu)。
        public EnumMap(Class < K > keyType)
// 其他構(gòu)造方法。
        public EnumMap(EnumMap < K, ? extends V > m ) 
        public EnumMap(Map < K, ? extends V > m )

所以 EnumMap 與 HashMap 的主要不同就是構(gòu)造方法需要傳遞類型參數(shù),此外 EnumMap 能依據(jù) key 的枚舉順序保證有序性,當(dāng) key 為枚舉類型時使用 EnumMap 的效率遠遠高于 HashMap。

問:簡單說說 EnumMap 的實現(xiàn)原理?

答:EnumMap 的實現(xiàn)原理依賴內(nèi)部兩個長度相同的數(shù)組,一個表示所有可能的鍵,一個表示對應(yīng)的值,當(dāng)放入 key-value 時首先會檢查鍵的類型,如果類型不對會拋出異常,否則調(diào)用 key 的 ordinal 獲取索引 index,并將值 value 放入值數(shù)組 vals[index] 中(注意:如果值 value 為 null,則為了區(qū)別真正的 null 與沒有值,EnumMap 會將 null 值包裝成一個特殊的對象)。

其構(gòu)造方法主要就是在初始化相關(guān)數(shù)組,如下:

        public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> implements java.io.Serializable, Cloneable {
            //key鍵的具體枚舉類型
            private final Class<K> keyType;
            // key的所有枚舉值
            private transient K[] keyUniverse;
            // EnumMap的存儲實現(xiàn),僅僅為一個枚舉成員個數(shù)長度的數(shù)組 
            private transient Object[] vals;

            ......

            // 構(gòu)造方法
            public EnumMap(Class<K> keyType) {
                // key的枚舉類型賦值
                this.keyType = keyType;
                // 獲取枚舉類的所有枚舉值存入數(shù)組緩存使用
                keyUniverse = getKeyUniverse(keyType);
                // 實例化枚舉值個數(shù)長度的數(shù)組 
                vals = new Object[keyUniverse.length];
            }
             ......
        }

其 put 操作的源碼如下:

        public V put (K key, V value )
        {
            //檢查key類型是不是構(gòu)造時的類型
            typeCheck(key);
            // 獲取枚舉成員在枚舉中的順序位置
            int index = key.ordinal();
            // 放值或者替換 //(注意:這里如果value為null這會進行包裝為Object和解包裝操作) 
            Object oldValue = vals[index];
            vals[index] = maskNull(value);
            if (oldValue == null) size++;
            return unmaskNull(oldValue);
        }
        // value為null時包裝成重寫過toString和hashCode方法的Object 
        private Object maskNull (Object value ){
            return (value == null ? NULL : value);
        }
        // value為null時從重寫過toString和hashCode方法的Object解包裝為null
        private V unmaskNull (Object value ){
            return (V) (value == NULL ? null : value);
        }

其獲取指定 key 的 value 的 get 方法實現(xiàn)如下:

    //注意這里如果value為null這會進解包裝操作,參見put 
        public V get (Object key ){
            return (isValidKey(key) ? unmaskNull(vals[((Enum) key).ordinal()]) : null);
        } 
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容