活久见的LinkedHashMap
随便聊聊
笔者大三,在2021.1.18入职字节实习生,干了四十天就休假跑路回去上课了。最近一大段时间过的非常松懈,现在报复性疯狂发布博客,哈哈。还是决定阅读JDK源码,从集合开始,希望能够读完核心的集合、AQS、线程池在等部分,最近对Java并发比较感兴趣也比较有体会,鬼知道能不能坚持到那个时候。笔者的文章可能不够详细,但会记录下来个人觉得比较核心的内容。
联系方式:qq 754647431
LinkedHashMap简介
核心原理:
LinkedHashMap的底层结构是:由于继承而产生的HashMap父类|LinkedHashMap自己的双向链表
所以LinkedHashMap只不过是在HashMap的基础上额外维护了一个双向链表罢了,仅此而已
那么问题来了:LinkedHashMap是如何在自己实现一点点方法的基础上,利用到HashMap中呢?
-----实际上是LinkedHashMap重写了HashMap的newNode函数,额外添加了一句话linkNodeLast§;这样就实现了在插入时维护双向链表,但是删除元素非常复杂,需要仔细看源码才行。这里先放下HashMap留给LinkedHashMap的后门方法。
# 这是HashMap留给LinkedHashMap的后门,
// Callbacks to allow LinkedHashMap post-actions
// 如果hashmap的节点被更新 则调用该方法
void afterNodeAccess(Node<K,V> p) { }
// 如果hashmap插入节点 则调用该方法
void afterNodeInsertion(boolean evict) { }
// 如果hashmap删除节点 则调用该方法
void afterNodeRemoval(Node<K,V> p) { }
这是我调试的时候截的图,可以看出,LinkedHashMap按顺序存储了双向链表结构,而HashMap也按hash存储了数据,每个数据都被存储了两次,并且结构体也不同
- 我们可以发现LinkedHashMap继承于HashMap,在HashMap已经实现Map接口的情况下,LinkedHashMap仍然实现了Map接口,实现Map接口会要求LinkedHashMap实现所有Map接口的方法。
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
- 我们可以发现,LinkedHashMap包含的函数非常少,甚至不包含put方法,这是因为LinkedHashMap继承了HashMap的put等方法。
- 我们来看看LinkedHashMap如何从HashMap获取数据,来维护自己的双向链表。
- LinkedHashMap重写了HashMap的newNode方法,每次HashMap需要插入节点的时候都需要newNode函数,这样LinkedHashMap就能够通过linkNodeLast§;来维护双向链表了。
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;
}
核心维护双向链表的函数
// link at the end of list
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;
}
}