概述
Hash table and linked list implementation of the <tt>Map</tt> interface, with predictable iteration order.
This implementation differs from <tt>HashMap</tt> in that it maintains a doubly-linked list running through all of its entries.
Map接口的hash表+链表实现(有可预测的iterator顺序);
LinkedHashMap是双向链表;
This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (<i>insertion-order</i>).
定义了iterator顺序,一般是 插入顺序;
Note that insertion order is not affected if a key is <i>re-inserted</i> into the map.
(A key <tt>k</tt> is reinserted into a map <tt>m</tt> if <tt>m.put(k, v)</tt> is invoked when <tt>m.containsKey(k)</tt> would return <tt>true</tt> immediately prior to the invocation.)
A special {@link #LinkedHashMap(int,float,boolean) constructor} is provided to create a linked hash map whose order of iteration is the order in which its entries were last accessed, from least-recently accessed to most-recently (<i>access-order</i>).
提供了一个 LinkedHashMap(int,float,boolean)构造器 创建一个linked hash map
This class provides all of the optional <tt>Map</tt> operations, and permits null elements.
LinkedHashMap允许null值;
A linked hash map has two parameters that affect its performance:<i>initial capacity</i> and <i>load factor</i>.
LinkedHashMap有2个影响性能的参数: initial capacity、load factor
Note that this implementation is not synchronized.
If multiple threads access a linked hash map concurrently, and at least one of the threads modifies the map structurally, it <em>must</em> be synchronized externally.
If no such object exists, the map should be "wrapped" using the {@link Collections#synchronizedMap Collections.synchronizedMap} method.
LinkedHashMap是线程非同步的;
如果多个线程并发访问LinkedHashMap,需要在外部同步;
同步方式:Collections.synchronizedMap;
The iterators returned by the <tt>iterator</tt> method of the collections returned by all of this class's collection view methods are <em>fail-fast</em>: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own <tt>remove</tt> method, the iterator will throw a {@link ConcurrentModificationException}.
iterator方法是fail-fast:如果在iterator的同时对结构进行修改,将会抛出ConcurrentModificationException;
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> { static class Entry<K,V> extends HashMap.Node<K,V> { LinkedHashMap.Entry<K,V> before, after; Entry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); } } /** * 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; // The iteration ordering method for this linked hash map: true for access-order, false for insertion-order. // 迭代排序:true->access-order、false->insertion-order final boolean accessOrder; // 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; } public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; } }
LinkedHashMap的扩展
accessOrder
构造参数accessOrder为true,get时会将该元素move到队尾;
LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>(10, 0.75F,true); linkedHashMap.put("a", "a"); linkedHashMap.put("b", "b"); linkedHashMap.put("c", "c"); linkedHashMap.put("d", "d"); System.out.println(linkedHashMap.toString()); // {a=a, b=b, c=c, d=d} linkedHashMap.get("c"); System.out.println(linkedHashMap.toString()); // {a=a, b=b, d=d, c=c} linkedHashMap.entrySet().stream().forEach(e -> System.out.print(" "+e)); // a=a b=b d=d c=c
removeEldestEntry
LinkedHashMap每次插入新的元素,都会调用removeEldestEntry方法,如果返回true,移除最老的元素;
static class FIFOCache<K, V> extends LinkedHashMap<K, V>{ private final int cacheSize; public FIFOCache(int cacheSize){ this.cacheSize = cacheSize; } // 当Entry个数超过cacheSize时,删除最老的Entry @Override protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return size() > cacheSize; } } FIFOCache<String, String> fifoCache = new FIFOCache<>(4); fifoCache.put("a", "a"); fifoCache.put("b", "b"); fifoCache.put("c", "c"); fifoCache.put("d", "d"); fifoCache.put("e", "e"); System.out.print(fifoCache); // {b=b, c=c, d=d, e=e}
链路
Put
// java.util.HashMap.put public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } // java.util.HashMap.putVal final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; 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); 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; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; } // java.util.LinkedHashMap.afterNodeInsertion void afterNodeInsertion(boolean evict) { // possibly remove eldest LinkedHashMap.Entry<K,V> first; if (evict && (first = head) != null && removeEldestEntry(first)) { // removeEldestEntry每次Put都要看下是否需要移除最老的元素 K key = first.key; removeNode(hash(key), key, null, false, true); } }
get
// java.util.LinkedHashMap.get public V get(Object key) { HashMap.Node<K,V> e; if ((e = getNode(hash(key), key)) == null) return null; if (accessOrder) afterNodeAccess(e); // 如果accessOrder=true -> 将访问的元素插入尾部 return e.value; } // java.util.LinkedHashMap.afterNodeAccess void afterNodeAccess(HashMap.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; } }
标签:hash,key,put,Entry,null,LinkedHashMap From: https://www.cnblogs.com/anpeiyong/p/17814575.html