­

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();  }

????

  1. LinkedHashMap ??? HashMap ?????????????? + ??? + ???????????????
  2. LinkedHashMap ?? HashMap ??????????????? Entry ??????????
  3. HashMap ?????????????????????? LinkedHashMap ??????????????????????????????????
  4. LinkedHashMap ???????? accessOrder ?????????????????????????????