前言
HashMap,比如你放了一堆key-value對進去,後面的話呢如果你要遍歷這個HashMap的話,遍歷的順序,並不是按照你插入的key-value的順序來的
LinkedHashMap,他會記錄你插入key-value的順序, 如果你在遍歷的時候,他是按照插入key-value對的順序給你遍歷出來的
LinkedHashMap是HashMap的一個子類。LinkedHashMap和TreeMap的區別,他們都可以維持key的順序,只是LinkedHashMap底層是基於鏈表來實現的,TreeMap是基於紅黑樹來實現順序的
LinkedHashMap其實原則上來說一些基本的原理和操作跟HashMap是差不多的,唯一主要的區別就是你在插入、覆蓋、刪除,他會記錄一下key-value對的順序,用一個鏈表來記錄,在遍歷的時候,就可以按照這個順序來遍歷
源碼剖析
在調用LinkedHashMap的put()方法的時候,一定會調用到HashMap的put()方法裏面去,調用完put()方法,其實就會調用afterNodeInsertion(evict);,這個方法就會去回調LinkedHahsMap裏面的子類的實現。
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry<K,V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
所以說就是在這裏,回調了這個方法,這個方法裏面,他就是實現了LinkedHashMap的邏輯,來記錄插入key-value對的順序,用一個鏈表來記錄。
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);
linkNodeLast(p);
return p;
}
將節點封裝爲了一個LinkedHashMap.Entry對象,然後使用linkNodeLast(p)這個東西,將這個節點掛到一個鏈表裏去。
LinkedHashMap有一個參數的,你可以在構造的時候傳入進去,accessOrder,默認他是false,如果是默認爲false的話,那麼你比如說你get一個key,或者是覆蓋這個key的值,都不會改變他在鏈表裏的順序。
但是如果accessOrder是true的話,那麼如果你get一個key,或者是覆蓋這個key的值,就會導致個key-value對順序會在鏈表裏改變,他會被挪動到鏈表的尾部去
你刪除某個元素的時候,就會將那個元素從鏈表裏給摘除
在迭代的時候,LinkedHashMap裏面會從鏈表的頭部開始迭代,這樣通過這個鏈表就可以維持他的一個順序