LinkedHashMap繼承自HashMap,同時(shí)也維護(hù)了元素的插入順序。內(nèi)部多了一個(gè)雙向循環(huán)鏈表的維護(hù),該鏈表是有序的,可以按元素插入順序或元素最近訪問順序(LRU)排列。來(lái)看下源碼吧。
支持原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處。
LinkedHashMap是一個(gè)維護(hù)了一個(gè)雙向鏈表的HashMap:
繼承關(guān)系
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
LinkedHashMap繼承自HashMap,最好先看下HashMap的源碼。
內(nèi)部節(jié)點(diǎn)
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
Entry繼承自HashMap.Node,同時(shí)增加了指向前一個(gè)和后一個(gè)節(jié)點(diǎn)的引用。
成員變量
transient LinkedHashMap.Entry<K,V> head; //鏈表頭結(jié)點(diǎn)
/**
* The tail (youngest) of the doubly linked list.
*/
transient LinkedHashMap.Entry<K,V> tail; //鏈表尾節(jié)點(diǎn)
final boolean accessOrder; //是否開啟最近最久未使用算法
構(gòu)造函數(shù)
public LinkedHashMap() {
super();
accessOrder = false;
}
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
主要的工作是設(shè)置accessOrder這個(gè)成員變量,其他的交給父類構(gòu)造函數(shù)。
核心方法
eldest方法
public Entry<K, V> eldest() {
LinkedEntry<K, V> eldest = header.nxt;
return eldest != header ? eldest : null;
}
該方法返回的就是鏈表頭部的節(jié)點(diǎn)。頭結(jié)點(diǎn)代表最久未訪問的節(jié)點(diǎn)。
看下get方法:
@Override public V get(Object key) {
/*
* This method is overridden to eliminate the need for a polymorphic
* invocation in superclass at the expense of code duplication.
*/
if (key == null) {
HashMapEntry<K, V> e = entryForNullKey;
if (e == null)
return null;
if (accessOrder)
makeTail((LinkedEntry<K, V>) e);
return e.value;
}
int hash = Collections.secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
e != null; e = e.next) { //遍歷鏈表
K eKey = e.key;
if (eKey == key || (e.hash == hash && key.equals(eKey))) { //若找到
if (accessOrder)
makeTail((LinkedEntry<K, V>) e); //將當(dāng)前節(jié)點(diǎn)放到鏈表尾部
return e.value; //返回節(jié)點(diǎn)的值
}
}
return null;
}
該方法先計(jì)算Hash值,然后根據(jù)Hash值確定桶,遍歷桶中的節(jié)點(diǎn),若找到,則返回該節(jié)點(diǎn)的值,并將該節(jié)點(diǎn)放到鏈表的末尾。所以頭結(jié)點(diǎn)就是最久為訪問的節(jié)點(diǎn)。
看張圖就清楚了:
這張圖中,我們先刪除了節(jié)點(diǎn)3,然后插入了節(jié)點(diǎn)6,接著訪問節(jié)點(diǎn)4,訪問時(shí)會(huì)先刪除節(jié)點(diǎn)4,并將節(jié)點(diǎn)4放入鏈表的末尾。
總結(jié)
LinkedHashMap實(shí)現(xiàn)了HashMap的快速訪問,同時(shí)也按訪問順序或插入順序維護(hù)了雙向鏈表。