LinkedHashMap担任HashMap并实现了Map接口,同时具有可预测的迭代顺序(凭据插入顺序排序)。它与HashMap的差异之处在于,昆山软件开发,维护了一条贯串其全部Entry的双向链表(因为特别维护了链表的干系,机能上要略差于HashMap,不外荟萃视图的遍历时间与元素数量成正比,而HashMap是与buckets数组的长度成正比的),可以认为它是散列表与链表的团结。
/** * 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; /** * 迭代顺序模式的标志位,假如为true,回收会见排序,不然,回收插入顺序 * 默认插入顺序(结构函数中默认配置为false) */ 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; }
LinkedHashMap的Entry实现也担任自HashMap,只不外多了指向前后的两个指针。
/** * HashMap.Node subclass for normal LinkedHashMap entries. */ 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); } }
你也可以通过结构函数来结构一个迭代顺序为会见顺序(accessOrder设为true)的LinkedHashMap,这个会见顺序指的是凭据最近被会见的Entry的顺序举办排序(从最近最少会见到最近最多会见)。基于这点可以简朴实现一个回收LRU(Least Recently Used)计策的缓存。
public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; }
LinkedHashMap复用了HashMap的大部门代码,所以它的查找实现长短常简朴的,独一稍微巨大点的操纵是担保会见顺序。
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; }
还记得这些afterNodeXXXX定名名目标函数吗?我们之前已经在HashMap中见地过了,这些函数在HashMap中只是一个空实现,是专门用来让LinkedHashMap重写实现的hook函数。
// 在HashMap.removeNode()的末端处挪用 // 将e从LinkedHashMap的双向链表中删除 void afterNodeRemoval(Node<K,V> e) { // unlink LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after; p.before = p.after = null; if (b == null) head = a; else b.after = a; if (a == null) tail = b; else a.before = b; } // 在HashMap.putVal()的末端处挪用 // evict是一个模式标志,假如为false代表buckets数组处于建设模式 // HashMap.put()函数对此标志配置为true void afterNodeInsertion(boolean evict) { // possibly remove eldest LinkedHashMap.Entry<K,V> first; // LinkedHashMap.removeEldestEntry()永远返回false // 制止了最年长元素被删除的大概(就像一个普通的Map一样) if (evict && (first = head) != null && removeEldestEntry(first)) { K key = first.key; removeNode(hash(key), key, null, false, true); } } // HashMap.get()没有挪用此函数,所以LinkedHashMap重写了get() // get()与put()城市挪用afterNodeAccess()来担保会见顺序 // 将e移动到tail,代表最近会见到的节点 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; } }
留意removeEldestEntry()
默认永远返回false,这时它的行为与普通的Map无异。假如你把removeEldestEntry()
重写为永远返回true,那么就有大概使LinkedHashMap处于一个永远为空的状态(每次put()
可能putAll()
城市删除头节点)。
一个较量公道的实现示例:
protected boolean removeEldestEntry(Map.Entry eldest){ return size() > MAX_SIZE; }