Java集合(八)--EnumMap簡(jiǎn)析

用于枚舉類(lèi)型鍵的專(zhuān)用Map實(shí)現(xiàn)琐凭。 EnumMap映射中的所有鍵必須來(lái)自創(chuàng)建映射時(shí)顯式或隱式指定的單個(gè)枚舉類(lèi)型。 枚舉映射在內(nèi)部表示為數(shù)組饶号, 枚舉映射按其鍵的自然順序(枚舉常量的聲明順序)維護(hù)撞叽。 這反映在集合視圖keySet(),entrySet()和values()返回的迭代器中也祠。集合視圖返回的迭代器非常一致:它們永遠(yuǎn)不會(huì)拋出ConcurrentModificationException昙楚,它們可能會(huì)也可能不會(huì)顯示出迭代進(jìn)行過(guò)程中對(duì)映射所做的修改的而對(duì)其造成的影響。不允許使用空鍵诈嘿,嘗試插入空鍵將拋出NullPointerException堪旧。但是,測(cè)試是否存在空鍵或刪除空鍵將正常運(yùn)行奖亚,且允許空值淳梦。同大多數(shù)集合一樣,EnumMap不是線(xiàn)程同步的昔字。

定義及說(shuō)明

定義如下:

public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
    implements java.io.Serializable, Cloneable{}

1爆袍、繼承了AbstractMap,即擁有Map基本的操作作郭。

2陨囊、實(shí)現(xiàn)了java.io.Serializable,即可序列化和反序列化

3夹攒、實(shí)現(xiàn)了Cloneable谆扎,即支持clone

我們?cè)倏匆幌滤臉?gòu)造方法:

//此映射的所有鍵的枚舉類(lèi)型的Class對(duì)象
private final Class<K> keyType;

//包含在keyType中的所有枚舉常量(用來(lái)緩存性能)
private transient K[] keyUniverse

//此映射的數(shù)組表示形式。
private transient Object[] vals;

//Map大小
private transient int size = 0;

//創(chuàng)建具有指定鍵類(lèi)型的空枚舉映射
public EnumMap(Class<K> keyType) {
        //指定此EnumMap的key的枚舉類(lèi)型的Class對(duì)象
        this.keyType = keyType;
        //返回包含在keyType中的所有值枚舉常量
        keyUniverse = getKeyUniverse(keyType);
        //根據(jù)KeyType中的枚舉常量的個(gè)數(shù)初始化vals數(shù)組
        vals = new Object[keyUniverse.length];
    }

//創(chuàng)建一個(gè)與m相同的Map
public EnumMap(EnumMap<K, ? extends V> m) {
        keyType = m.keyType;
        keyUniverse = m.keyUniverse;
        vals = m.vals.clone();
        size = m.size;
    }

//創(chuàng)建從指定Map初始化的枚舉映射芹助。 如果指定的映射是EnumMap實(shí)例堂湖,則此構(gòu)造函數(shù)的行為與EnumMap(EnumMap)相同闲先。 否則,指定的映射必須至少包含一個(gè)映射(以確定新的枚舉映射的鍵類(lèi)型)
public EnumMap(Map<K, ? extends V> m) {
        //判斷是否為EnumMap類(lèi)型
        if (m instanceof EnumMap) {
            EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m;
            keyType = em.keyType;
            keyUniverse = em.keyUniverse;
            vals = em.vals.clone();
            size = em.size;
        } else {
            //不是Enum類(lèi)型
            if (m.isEmpty())
                throw new IllegalArgumentException("Specified map is empty");
            keyType = m.keySet().iterator().next().getDeclaringClass();
            keyUniverse = getKeyUniverse(keyType);
            vals = new Object[keyUniverse.length];
            putAll(m);
        }
    }

需要注意:

1无蜂、keyUniverse數(shù)組中包含的元素伺糠,是keyType枚舉類(lèi)型中所有的枚舉常量。且vals數(shù)組長(zhǎng)度與keyUniverse數(shù)組長(zhǎng)度相同斥季。

2训桶、使用第三個(gè)構(gòu)造函數(shù)創(chuàng)建EnumMap的時(shí)候,如果指定的映射是EnumMap實(shí)例酣倾,則此構(gòu)造函數(shù)的行為與第二個(gè)構(gòu)造函數(shù)相同舵揭。 否則,指定的Map中必須至少包含一個(gè)映射躁锡,用來(lái)確定新的枚舉映射的鍵類(lèi)型午绳。

源碼簡(jiǎn)析

老規(guī)矩,看put()方法:

public V put(K key, V value) {
        //檢查key是不是正確類(lèi)型
        typeCheck(key);
        //獲取key在枚舉常量的聲明順序(第幾個(gè)聲明的)
        int index = key.ordinal();
        //獲取在當(dāng)前index位置的值
        Object oldValue = vals[index];
        //判斷value是否為空映之,并賦值
        vals[index] = maskNull(value);
        //判斷oldValue是否為空拦焚,已確定是添加了元素,還是修改了值
        if (oldValue == null)
            //如果是添加了元素杠输,則數(shù)組長(zhǎng)度加1
            size++;
        //根據(jù)value的值判斷value是否為空赎败,并返回
        return unmaskNull(oldValue);
    }

//如果key不是此枚舉集的正確類(lèi)型,則引發(fā)異常
private void typeCheck(K key) {
        Class<?> keyClass = key.getClass();
        if (keyClass != keyType && keyClass.getSuperclass() != keyType)
            throw new ClassCastException(keyClass + " != " + keyType);
    }

//根據(jù)value是否為空給其賦值
private Object maskNull(Object value) {
        return (value == null ? NULL : value);
    }

//根據(jù)value的值判斷其是否為空
@SuppressWarnings("unchecked")
    private V unmaskNull(Object value) {
        return (V)(value == NULL ? null : value);
    }

由上面的分析我們得出蠢甲,假如i為數(shù)組keyUniverse的某個(gè)角標(biāo)僵刮,則keyUniverse[i]在數(shù)組EnumMap中所對(duì)應(yīng)的值為vals[i]。而且鹦牛,EnumMap的鍵值對(duì)的映射是keyUniverse數(shù)組與vals數(shù)組中相同位置的元素的映射妓笙。

為什么TreeMap永遠(yuǎn)不會(huì)拋出ConcurrentModificationException ?請(qǐng)結(jié)合fail-fast想一想

Java集合(三)--fail-fast機(jī)制

好了能岩,本篇文章到此結(jié)束寞宫。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市拉鹃,隨后出現(xiàn)的幾起案子辈赋,更是在濱河造成了極大的恐慌,老刑警劉巖膏燕,帶你破解...
    沈念sama閱讀 211,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钥屈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡坝辫,警方通過(guò)查閱死者的電腦和手機(jī)篷就,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)近忙,“玉大人竭业,你說(shuō)我怎么就攤上這事智润。” “怎么了未辆?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,435評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵窟绷,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我咐柜,道長(zhǎng)兼蜈,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,509評(píng)論 1 284
  • 正文 為了忘掉前任拙友,我火速辦了婚禮为狸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘遗契。我一直安慰自己辐棒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布姊途。 她就那樣靜靜地躺著涉瘾,像睡著了一般知态。 火紅的嫁衣襯著肌膚如雪捷兰。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,837評(píng)論 1 290
  • 那天负敏,我揣著相機(jī)與錄音贡茅,去河邊找鬼。 笑死其做,一個(gè)胖子當(dāng)著我的面吹牛顶考,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播妖泄,決...
    沈念sama閱讀 38,987評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼驹沿,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蹈胡?” 一聲冷哼從身側(cè)響起渊季,我...
    開(kāi)封第一講書(shū)人閱讀 37,730評(píng)論 0 267
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎罚渐,沒(méi)想到半個(gè)月后却汉,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,194評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡荷并,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評(píng)論 2 327
  • 正文 我和宋清朗相戀三年合砂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片源织。...
    茶點(diǎn)故事閱讀 38,664評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡翩伪,死狀恐怖微猖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幻工,我是刑警寧澤励两,帶...
    沈念sama閱讀 34,334評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站囊颅,受9級(jí)特大地震影響当悔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜踢代,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評(píng)論 3 313
  • 文/蒙蒙 一盲憎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胳挎,春花似錦饼疙、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,764評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至医窿,卻和暖如春磅甩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背姥卢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,997評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工卷要, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人独榴。 一個(gè)月前我還...
    沈念sama閱讀 46,389評(píng)論 2 360
  • 正文 我出身青樓僧叉,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親棺榔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓶堕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評(píng)論 2 349