上两篇文章分别介绍了《HashMap的原理和源码解析》和《HashTable的原理和源码解析》,至此,第三篇文章就是LinkedHashMap的原理特性介绍以及部分源码的解析。
LinkedHashMap的特性
-
LinkedHashMap 直接继承HashMap,所以基础特性、数据结构都没什么变化。
-
LinkedHashMap 在HashMap的基础上,新增一个双向链表,每个Node增加了一个before,after,表示上一个结点和下一个结点。不过,双向链表顺序是根据插入或者访问顺序来决定的。before、after跟hashMap的next表达的含义是不一样的,next表示hash桶内部顺序,而before、after表示插入或访问顺序。
-
在上面的图可以很清晰的看到,蓝色的线表示的就是访问或者顺序,串联成为一个双向链表。由此也可以猜想到LinkedHashMap的原理,就是在HashMap插入、访问、删除等操作后,及时修改LinkedHashMap的双向链表,维持顺序。
LinkedHashMap 源码分析
重要的数据结构
static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> {
LinkedHashMapEntry<K,V> before, after;
LinkedHashMapEntry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
LinkedHashMapEntry继承自HashMap的Node,内部多了before, after,形成一个双向链表。
transient LinkedHashMapEntry<K,V> head; // 双向链表头部结点
transient LinkedHashMapEntry<K,V> tail; // 双向链表尾部结点
final boolean accessOrder;// 是否按照访问顺序排序,若false,则按照插入顺序
接下来看下LinkedHashMap内部常用的比较重要的方法:
// 插入P结点到链表尾部
private void linkNodeLast(LinkedHashMapEntry<K,V> p) {
LinkedHashMapEntry<K,V> last = tail;
tail = p;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}
linkNodeLast 顾名思义就是把结点P挂在链表尾部,如果链表为空,就将P设置为头节点。
// 将中间的src节点(链表)替换成 dest 节点(链表)
private void transferLinks(LinkedHashMapEntry<K,V> src, LinkedHashMapEntry<K,V> dst) {
LinkedHashMapEntry<K,V> b = dst.before = src.before;
LinkedHashMapEntry<K,V> a = dst.after = src.after