[JDK1.8]LinkedHashMap原始碼淺析
阿新 • • 發佈:2018-12-14
引言
上篇我們瞭解了JDK1.7中LinkedHashMap的原始碼,這篇文章試著分析一下JDK1.8中LinkedHashMap的原始碼(由於1.8HashMap做了優化,所以作為其子類的LinkedHashMap自然也做了一些修改.基於1.8的HashMap原始碼分析在之前的文章已經有了,不多闡述)
LinkedHashMap的成員變數
區別於1.7中的成員變數標誌位置只有一個header節點; JDK1.8中有一個head和一個tail節點;
JDK1.7
/**
* The head of the doubly linked list.
*/
private transient Entry<K,V> header;
/**
* The iteration ordering method for this linked hash map: <tt>true</tt>
* for access-order, <tt>false</tt> for insertion-order.
*
* @serial
*/
private final boolean accessOrder;
JDK1.8
private static final long serialVersionUID = 3801124242820219131L;
// 用於指向雙向連結串列的頭部, 雙向連結串列頭節點(最老)
transient LinkedHashMap.Entry<K,V> head;
//用於指向雙向連結串列的尾部,雙向列表尾節點(最新)
transient LinkedHashMap.Entry<K,V> tail;
/**
* 用來指定LinkedHashMap的迭代順序,
* true則表示按照基於訪問的順序來排列,意思就是最近使用的entry,放在連結串列的最末尾
* false則表示按照插入順序來
*/
final boolean accessOrder;
建構函式
1.8
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;
}
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
/**
* Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
* with the default initial capacity (16) and load factor (0.75).
*/
public LinkedHashMap() {
super();
accessOrder = false;
}
/**
* Constructs an insertion-ordered <tt>LinkedHashMap</tt> instance with
* the same mappings as the specified map. The <tt>LinkedHashMap</tt>
* instance is created with a default load factor (0.75) and an initial
* capacity sufficient to hold the mappings in the specified map.
*
* @param m the map whose mappings are to be placed in this map
* @throws NullPointerException if the specified map is null
*/
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
putMapEntries(m, false);
}
/**
* Constructs an empty <tt>LinkedHashMap</tt> instance with the
* specified initial capacity, load factor and ordering mode.
*
* @param initialCapacity the initial capacity
* @param loadFactor the load factor
* @param accessOrder the ordering mode - <tt>true</tt> for
* access-order, <tt>false</tt> for insertion-order
* @throws IllegalArgumentException if the initial capacity is negative
* or the load factor is nonpositive
*/
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
1.8的建構函式和1.7的建構函式有差異的在接收map的建構函式; 1.7
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super(m);
accessOrder = false;
}
super(m)呼叫hashMap的建構函式進行初始化:
public HashMap(Map<? extends K, ? extends V> m) {
this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
inflateTable(threshold);
putAllForCreate(m);
}
putAllForCreate(m)
內部迴圈呼叫putForCreate(K key, V value)
private void putForCreate(K key, V value) {
int hash = null == key ? 0 : hash(key);
int i = indexFor(hash, table.length);
/**
* Look for preexisting entry for key. This will never happen for
* clone or deserialize. It will only happen for construction if the
* input Map is a sorted map whose ordering is inconsistent w/ equals.
*/
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k)))) {
e.value = value;
return;
}
}
//如果沒有存在的key對應的Entry,那麼新建Entry
createEntry(hash, key, value, i);
}
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, e);
size++;
}
1.8
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
putMapEntries(m, false);
}
/**
* Implements Map.putAll and Map constructor
*
* @param m the map
* @param evict false when initially constructing this map, else
* true (relayed to method afterNodeInsertion).
*/
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
int s = m.size();
if (s > 0) {
if (table == null) { // pre-size
float ft = ((float)s / loadFactor) + 1.0F;
int t = ((ft < (float)MAXIMUM_CAPACITY) ?
(int)ft : MAXIMUM_CAPACITY);
if (t > threshold)
threshold = tableSizeFor(t);
}
else if (s > threshold)
resize();
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
K key = e.getKey();
V value = e.getValue();
//evict false when initially constructing this map, else true (relayed to method afterNodeInsertion).
//呼叫putVal函式
putVal(hash(key), key, value, false, evict);
}
}
}
Entry
LinkedHashMap 1.8中的Entry和1.7中的區別不大,都是Map.Entry<K,V>
的實現
同樣的:
Entry裡面的屬性:
1、K key
2、V value
3、Entry<K, V> next
4、int hash
5、Entry<K, V> before
6、Entry<K, V> after
其中前面四個,也就是紅色部分是從HashMap.Entry中繼承過來的;後面兩個,也就是藍色部分是LinkedHashMap獨有的。不要搞錯了next和before、After,next是用於維護HashMap指定table位置上連線的Entry的順序的,before、After是用於維護Entry插入的先後順序的。
put
get 查
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;
}
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}