LinkedHashMap 源码分析-
HashMap 是无序的,TreeMap 是根据 key 进行排序,而 LinkedHashMap,是根据插入顺序排序的。
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>{......}
复制代码
LinkedHashMap 继承了 HashMap ,所以它拥有 HashMap 的所有特性,额外的,LinkedHashMap 还包含了两大特性:
按照插入顺序进行访问;
实现了访问最少最先删除功能,把很久都没有访问的 key 自动删除。
LinkedHashMap 链表结构
LinkedHashMap 把 Map 的元素都串联起来,形成了一个链表,而链表可以保证顺序,如此就实现了按插入顺序访问。
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); } }
private static final long serialVersionUID = 3801124242820219131L;
/** * 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: <tt>true</tt> * for access-order, <tt>false</tt> for insertion-order. * * @serial */ final boolean accessOrder;
复制代码
transient LinkedHashMap.Entry<K,V> head;链表头
transient LinkedHashMap.Entry<K,V> tail;链表尾
static class Entry<K,V> extends HashMap.Node<K,V> {......} 继承 Node,数组中元素属性增加了 before 和 after 属性
final boolean accessOrder; 控制两种访问模式的字段,true 按照访问顺序,会把经常访问的 key 放到队尾,false 按照插入顺序提供访问
按照顺序新增
新增节点,并追加到链表的尾部。LinkedHashMap 通过新增头节点、尾节点,给每个节点增加 before、after 属性,每次新增时,都把节点追加到尾节点等手段,在新增的时候,就已经维护了按照插入顺序的链表结构了。
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; } }
复制代码
tail = p;新增节点等于位节点
if (last == null) head = p; last 为空,说明链表为空,首尾节点相等
else { p.before = last; last.after = p; }链表有数据,直接建立新增节点和上个尾节点之间的前后关系即可
按照顺序访问
LinkedHashMap 只提供了单向遍历访问,按照插入的顺序从头到尾进行访问。
通过迭代器进行访问,迭代器初始化的时候,默认从头节点开始访问,在迭代的过程中,不断访问当前节点的 after 节点。
LinkedHashIterator() { next = head; expectedModCount = modCount; current = null; }
final LinkedHashMap.Entry<K,V> nextNode() { LinkedHashMap.Entry<K,V> e = next; if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (e == null) throw new NoSuchElementException(); current = e; next = e.after; return e; }
复制代码
next = head;头节点作为第一个访问的节点
if (modCount != expectedModCount) throw new ConcurrentModificationException(); 校验
next = e.after; 通过链表的 after 结构,找到下一个迭代的节点
评论