java.util系列源碼解讀之LinkedHashMap

LinkedHashMap是繼承自HashMap,并實(shí)現(xiàn)Map接口.所以他擁有HashMap的結(jié)構(gòu),同時(shí)他又有LinkedList的結(jié)構(gòu)(雙向鏈表的結(jié)構(gòu)-環(huán)形的).由于LinkedHashMap中維護(hù)了一個(gè)雙向鏈表結(jié)構(gòu),所以在LinkedHashMap中的某些遍歷操作是直接針對(duì)的雙向鏈表的(例如:contains操作,Iterator操作).

下面是LinkedHashMap中entry結(jié)構(gòu):

// 繼承自HashMap中的entry,并增加了兩個(gè)額外的屬性
private static class Entry<K,V> extends HashMap.Entry<K,V> {
    // These fields comprise the doubly linked list used for iteration.
    Entry<K,V> before, after;

    Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
        super(hash, key, value, next);
    }
}

類定義

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>

成員變量(擁有HashMap中所有的非私有成員變量)

修飾符 變量名 作用
private transient Entry<K,V> header 鏈表結(jié)構(gòu)的頭結(jié)點(diǎn)(hash值取的-1)
private final boolean accessOrder 是否讓鏈表隨機(jī)訪問(true隨機(jī)get方法的影響,false就是插入順序)

方法

初始化方法init()
在構(gòu)造函數(shù)中被調(diào)用,會(huì)初始化鏈表的頭結(jié)點(diǎn)header

@Override
void init() {
    header = new Entry<>(-1, null, null, null);
    header.before = header.after = header;
}

添加元素put()
繼承自HashMap方法,且沒有重寫,所以它的數(shù)組結(jié)構(gòu)跟HashMap是一樣的;只是它重寫了addEntry()和createEntry()方法(這兩個(gè)方法會(huì)在put的時(shí)候被調(diào)用到),這兩個(gè)方法會(huì)增多一個(gè)雙向鏈表的結(jié)構(gòu).下面講解:

void addEntry(int hash, K key, V value, int bucketIndex) {
    // 調(diào)用父類HashMap中的addEntry()方法(會(huì)調(diào)用createEntry()方法)
    super.addEntry(hash, key, value, bucketIndex); 

    // Remove eldest entry if instructed
    Entry<K,V> eldest = header.after;
    // 移除老的Entry(不會(huì)執(zhí)行,除非子類重寫removeEldestEntry方法)
    if (removeEldestEntry(eldest)) {
        removeEntryForKey(eldest.key);
    }
}

void createEntry(int hash, K key, V value, int bucketIndex) {
    HashMap.Entry<K,V> old = table[bucketIndex];
    Entry<K,V> e = new Entry<>(hash, key, value, old);
    table[bucketIndex] = e;
    
    // 雙向鏈表的操作,在header節(jié)點(diǎn)前面鏈接e節(jié)點(diǎn)
    // 所以每次添加的新的entry,在雙向鏈表中的位置始終是在header前面
    e.addBefore(header);
    size++;
}

/**
* Entry類中的addBefore()方法
* 在existingEntry節(jié)點(diǎn)前增加當(dāng)前調(diào)用方法的實(shí)例節(jié)點(diǎn)
**/
private void addBefore(Entry<K,V> existingEntry) {
    after  = existingEntry;
    before = existingEntry.before;
    before.after = this;
    after.before = this;
}

獲取元素get()
跟HashMap是一樣的, 直接調(diào)用的父類HashMap中的getEntry()方法.

public V get(Object key) {
    Entry<K,V> e = (Entry<K,V>)getEntry(key);
    if (e == null)
        return null;
    
    // 增加隨機(jī)訪問性
    e.recordAccess(this);
    return e.value;
}

/**
* Entry類中的方法
**/
void recordAccess(HashMap<K,V> m) {
    LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
    // 如果允許隨機(jī)訪問則移除此節(jié)點(diǎn),再把該節(jié)點(diǎn)重新放在雙向鏈表的header前面
    if (lm.accessOrder) {
        lm.modCount++;
        remove();
        addBefore(lm.header);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖嫉晶,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異田篇,居然都是意外死亡替废,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門泊柬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來椎镣,“玉大人,你說我怎么就攤上這事兽赁∽创穑” “怎么了冷守?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)惊科。 經(jīng)常有香客問我拍摇,道長(zhǎng),這世上最難降的妖魔是什么馆截? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任充活,我火速辦了婚禮,結(jié)果婚禮上蜡娶,老公的妹妹穿的比我還像新娘混卵。我一直安慰自己,他們只是感情好窖张,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布淮菠。 她就那樣靜靜地躺著,像睡著了一般荤堪。 火紅的嫁衣襯著肌膚如雪合陵。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天澄阳,我揣著相機(jī)與錄音拥知,去河邊找鬼。 笑死碎赢,一個(gè)胖子當(dāng)著我的面吹牛低剔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播肮塞,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼襟齿,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了枕赵?” 一聲冷哼從身側(cè)響起猜欺,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拷窜,沒想到半個(gè)月后开皿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡篮昧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年赋荆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片懊昨。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡窄潭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酵颁,到底是詐尸還是另有隱情嫉你,我是刑警寧澤信认,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站均抽,受9級(jí)特大地震影響嫁赏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜油挥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一潦蝇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧深寥,春花似錦攘乒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至闰集,卻和暖如春沽讹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背武鲁。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工爽雄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人沐鼠。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓挚瘟,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親饲梭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子乘盖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

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