**Java源碼之LinkedHashMap**
轉載請注明出處:[http://blog.csdn.net/itismelzp/article/details/50554412](http://blog.csdn.net/itismelzp/article/details/50554412)
# 一、LinkedHashMap概述
LinkedHashMap是Map接口的哈希表和鏈接列表實現,具有**可預知的迭代順序**。此實現與 HashMap 的不同之處在于,LinkedHashMap維護著一個運行于所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序,該迭代順序通常就是將鍵插入到映射中的順序(插入順序)。注意,如果在映射中重新插入鍵,則插入順序不受影響。(如果在調用 m.put(k, v) 前 m.containsKey(k) 返回了 true,則調用時會將鍵 k 重新插入到映射 m 中。)
注意,此實現不是同步的。如果多個線程同時訪問鏈接的哈希映射,而其中至少一個線程從結構上修改了該映射,則它必須 保持外部同步。這一般通過對自然封裝該映射的對象進行同步操作來完成。如果不存在這樣的對象,則應該使用 Collections.synchronizedMap 方法來“包裝”該映射。
# 二、數據結構
數組 + 雙鏈表結構
~~~
/**
* 雙鏈表結點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);
}
}
~~~
# 三、LinkedHashMap源碼
### 1.頭文件
~~~
package java.util;
import java.util.function.Consumer;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.io.IOException;
~~~
### 2.繼承與實現關系
~~~
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
~~~
### 3.屬性
~~~
/**
* 雙鏈表的頭結點
*/
transient LinkedHashMap.Entry<K,V> head;
/**
* 雙鏈表的尾結點
*/
transient LinkedHashMap.Entry<K,V> tail;
/**
* 迭代順序
* true:訪問順序
* false:插入順序
*/
final boolean accessOrder;
~~~
### 4.構造方法
~~~
/**
* 構造方法一:
* 指定初始容量和裝載因子
* 順序規則:插入順序
*/
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;
}
/**
* 構造方法二:
* 指定初始容量并使用默認裝載因子(0.75)
* 順序規則:插入順序
*/
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
/**
* 構造方法三:
* 使用默認初始容量(16)和默認裝載因子(0.75)
* 順序規則:插入順序
*/
public LinkedHashMap() {
super();
accessOrder = false;
}
/**
* 構造方法四:
* 使用指定Map來構造
* 順序規則:插入順序
*/
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
putMapEntries(m, false);
}
/**
* 構造方法五:
* 指定初始容量、裝載因子和順序規則構造
*
*/
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
~~~
### 5.方法
### (1) 存儲數據
LinkedListHashMap并未重寫HashMap中的put方法。
具體實現可參考[【](http://blog.csdn.net/itismelzp/article/details/50525647)[Java源碼之HashMap】](http://blog.csdn.net/itismelzp/article/details/50525647)[](http://blog.csdn.net/itismelzp/article/details/50525647)中put與putValue方法。
### (2) 讀取數據
~~~
/**
* 如果key存在返回對應的value
* 如果key不存在返回指定的null
*/
public V get(Object key) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return null;
if (accessOrder)
afterNodeAccess(e);
return e.value;
}
/**
* 如果key存在返回對應的value
* 如果key不存在返回指定的defaultValue
*/
public V getOrDefault(Object key, V defaultValue) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return defaultValue;
if (accessOrder)
afterNodeAccess(e);
return e.value;
}
~~~
### 6.迭代
集合中的類都有一個共同的迭代方式,就是先把這個集合轉化成Set視圖,然后再對這個Set視圖進行迭代。
~~~
/**
* 返回一個包含此Map所有元素的Set視圖(實際是LinkedEntrySet類)
* 改變Map也會改變視圖
*/
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
}
/**
* 內部類LinkedEntrySet
* 里面封閉了迭代方法
*/
final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> {
public final int size() { return size; }
public final void clear() { LinkedHashMap.this.clear(); }
public final Iterator<Map.Entry<K,V>> iterator() {
return new LinkedEntryIterator();
}
public final boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Node<K,V> candidate = getNode(hash(key), key);
return candidate != null && candidate.equals(e);
}
public final boolean remove(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Object value = e.getValue();
return removeNode(hash(key), key, value, true, true) != null;
}
return false;
}
public final Spliterator<Map.Entry<K,V>> spliterator() {
return Spliterators.spliterator(this, Spliterator.SIZED |
Spliterator.ORDERED |
Spliterator.DISTINCT);
}
public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
if (action == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
action.accept(e);
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
~~~