1. 特點
-
繼承HashMap
-
Entry繼承HashMap的Node
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); } }
-
accessOrder:true訪問順序,false插入順序,測試代碼如下
public static void main(String[] args) { LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(0, 0.75f, true);// false map.put("1", "value1"); map.put("2", "value2"); map.put("3", "value3"); print(map); map.get("2"); //map.getOrDefault("2","default"); print(map); } accessOrder = true 1 value1 2 value2 3 value3 -------------------------------------- 1 value1 3 value3 2 value2 -------------------------------------- accessOrder = false 1 value1 2 value2 3 value3 -------------------------------------- 1 value1 2 value2 3 value3 --------------------------------------
如果爲false,get之後Entry存儲順序還是put的順序,如果爲true擇在get之後會把get的Entry放到隊列尾部。
2. 構造方法
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
this.accessOrder = false;
}
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
this.accessOrder = false;
}
public LinkedHashMap() {
super();
this.accessOrder = false;
}
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
this.accessOrder = false;
this.putMapEntries(m, false);
}
// 實現Lru效果要實現3個參數構造方法
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
3. 增
LinkedHashMap的put直接調用了HashMap的put方法。
3.1 HashMap的put方法中newNode方法
put方法把一個Entry put到Map中,在HashMap中調用newNode生成的是HashMap.Node,在LinkedHashMap中newNode生成的是LinkedHashMap.Entry,這裏就是爲啥LinkeHashMap的afterNodeAccess中Node<K, V> e 強轉成 (LinkedHashMap.Entry<K, V>) e 不報錯的原因。
if ((p = tab[i = (n - 1) & hash]) == null) {
tab[i] = this.newNode(hash, key, value, null);
}else{
...
this.newNode(hash, key, value, null);
}
// HashMap中實現的該方法
Node<K, V> newNode(int hash, K key, V value, Node<K, V> next) {
return new Node<>(hash, key, value, next);
}
// LinkedHashMap中實現的該方法
Node<K, V> newNode(int hash, K key, V value, Node<K, V> e) {
LinkedHashMap.Entry<K, V> p =
new LinkedHashMap.Entry<K, V>(hash, key, value, e);
// 把生成的節點放到尾部 詳見3.2
this.linkNodeLast(p);
return p;
}
3.2 linkNodeLast
把新生成的Node放到鏈表尾部
// link at the end of list
private void linkNodeLast(LinkedHashMap.Entry<K, V> p) {
LinkedHashMap.Entry<K, V> last = this.tail;
this.tail = p;
if (last == null) {
this.head = p;
} else {
p.before = last;
last.after = p;
}
}
3.3 HashMap的put方法中的this.afterNodeAccess(e)
下面是HashMap的put方法中的代碼片段:
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null) {
e.value = value;
}
this.afterNodeAccess(e);
return oldValue;
}
其中調用了this.afterNodeAccess(e),在HashMap中這是一個空方法,LinkedHashMap中實現了這個方法如下 :
@Override
void afterNodeAccess(Node<K, V> e) { // move node to last
LinkedHashMap.Entry<K, V> last;
if (this.accessOrder && (last = this.tail) != e) {
LinkedHashMap.Entry<K, V> p =
(LinkedHashMap.Entry<K, V>) e;
LinkedHashMap.Entry<K, V> b = p.before;
LinkedHashMap.Entry<K, V> a = p.after;
p.after = null;
if (b == null) {
this.head = a;
} else {
b.after = a;
}
if (a != null) {
a.before = b;
} else {
last = b;
}
if (last == null) {
this.head = p;
} else {
p.before = last;
last.after = p;
}
this.tail = p;
++this.modCount;
}
}
從註釋可以看出,將Node移動到鏈表尾部 , 併爲LinkedHashMap.Entry的after和before賦值。
4. 查
@Override
public V get(Object key) {
Node<K, V> e;
if ((e = this.getNode(hash(key), key)) == null) {
return null;
}
if (this.accessOrder) {
// 詳見3.2
this.afterNodeAccess(e);
}
return e.value;
}
如果設置了accessOrder爲訪問順序,那麼會把get到的Entry移動到尾部。