LinkedHashMap的特殊之处
- 2019 年 10 月 3 日
- 筆記
????
??????????LinkedHashMap?HashMap?????? ??????????? ??????????????HashMap??????LinkedHashMap????JDK8?
????????
1?????
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
LinkedHashMap?HashMap??????HashMap????LinkedHashMap???
2?Entery<K, V> head?tail : ????
/** * The head (eldest) of the doubly linked list. */ transient LinkedHashMap.Entry<K,V> head; /** * The tail (youngest) of the doubly linked list. */ transient LinkedHashMap.Entry<K,V> tail; // Entry???????????????????? 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); } }
3?accessOrder????true???????????????????????????false,???????
/** * 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;
??????????false, ??????????? ???????????
public LinkedHashMap() { super(); accessOrder = false; } // ??accessOrder public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; }
????????????????????HashMap??????????????????????????????????
/** * ?????? */ @Test public void test_accessOrder_false() { // accessOrder ???false,?????? Map<String, String> map = new LinkedHashMap<>(); map.put("????", "????"); map.put("Andy", "???"); map.put("eson", "???"); map.put("??", "??"); for(Map.Entry<String, String> entry : map.entrySet()) { System.out.println("key:" + entry.getKey()); } }
output: ??????????????????????????????????????????????HashMap????????
key:????, value:???? key:Andy, value:??? key:eson, value:??? key:??, value:??
???????????????
/** * ?????? */ @Test public void test_accessOrder_true() { // ??accessOrder = true Map<String, String> map = new LinkedHashMap<>(10, 0.75f, true); map.put("????", "????"); map.put("Andy", "???"); map.put("eson", "???"); map.put("??????", "??????"); for(Map.Entry<String, String> entry : map.entrySet()) { System.out.println("key:" + entry.getKey() + ", value:" + entry.getValue()); } System.out.println("---------?Andy?????-------------"); map.get("Andy"); for(Map.Entry<String, String> entry : map.entrySet()) { System.out.println("key:" + entry.getKey() + ", value:" + entry.getValue()); } System.out.println("--------------??????----------------"); map.put("James", "23"); for(Map.Entry<String, String> entry : map.entrySet()) { System.out.println("key:" + entry.getKey() + ", value:" + entry.getValue()); } }
output: ????????????put????get????????????????
key:????, value:???? key:Andy, value:??? key:eson, value:??? key:??????, value:?????? ---------?Andy?????------------- key:????, value:???? key:eson, value:??? key:??????, value:?????? key:Andy, value:??? --------------??????---------------- key:????, value:???? key:eson, value:??? key:??????, value:?????? key:Andy, value:??? key:James, value:23
?????????????????????? ????????????
????????
1?put??
?????????????????????????????? ??LinkedHashMap?HashMap????????????????????????????????? ????put???????????
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; // table???????????????????? if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; // ??key?hash? ? ??????????????? if ((p = tab[i = (n - 1) & hash]) == null) // ???????? tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; // ???????????????????????? if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) // ??????????????????????????????????????? e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { // ????? for (int binCount = 0; ; ++binCount) { // ????????????????? -> ??? if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); // ????????????????????????????binCount,?????????????-1? if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st // ?????? treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } // ?????key, ???value if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value? // ???????????LinkedHashMap?? afterNodeAccess(e); return oldValue; } } ++modCount; // ?????????????????????????????? if (++size > threshold) resize(); // ???????????LinkedHashMap?? afterNodeInsertion(evict); return null; }
???????
- ????????newNode????????????LinkeHashMap?????????
- ?????key??value?????afterNodeAccess???????HashMap????????????????LinkeHashMap????
// Callbacks to allow LinkedHashMap post-actions void afterNodeAccess(Node<K,V> p) { }
- ?????????afterNodeInsertion??????????????LinkeHashMap?????
void afterNodeInsertion(boolean evict) { }
2?newNode()??
????LinkedHashMap??newNode()?????????????????????
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; } private void linkNodeLast(LinkedHashMap.Entry<K,V> p) { LinkedHashMap.Entry<K,V> last = tail; tail = p; // ???????????????????? if (last == null) head = p; else { // ?????????????????? p.before = last; last.after = p; } }
?????? LinkedHashMap????HashMap????????????????????????????????????
put() -> putVal() -> newNode() -> linkNodeLast
3?afterNodeAccess??
void afterNodeAccess(Node<K,V> e) { // move node to last LinkedHashMap.Entry<K,V> last; // ??accessOrder=true,???????????????????????????? if (accessOrder && (last = tail) != e) { LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after; // ?p???????null p.after = null; // ??e?????????, ???????????????? if (b == null) head = a; else // e?????????, ??e???????????????????????????? b.after = a; // e?????????, ??e????????????????e????????? if (a != null) a.before = b; else // ????????e????? last = b; // ????????e?????????????????? if (last == null) head = p; else { // ??????? p.before = last; last.after = p; } tail = p; ++modCount; } }
?????????????????????????????????????????????????????????????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; }
4?afterNodeInsertion??
?????????????????
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); } } // ??false, ??LinkedHashMap??????????????????????????? protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return false; }
??????????????????? ??LRUCache : ??????????????
5?Entry??forEach??
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(); }
????
- LinkedHashMap ??? HashMap ?????????????? + ??? + ???????????????
- LinkedHashMap ?? HashMap ??????????????? Entry ??????????
- HashMap ?????????????????????? LinkedHashMap ??????????????????????????????????
- LinkedHashMap ???????? accessOrder ?????????????????????????????