LinkedHashMa源码解析
Posted rocker-pg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LinkedHashMa源码解析相关的知识,希望对你有一定的参考价值。
LinkedHashMap(jdk 1.8.0_231)
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
// 构建新的entry节点
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
tail = p;
if (last == null)
// 如果原先的尾节点为null的话,说明这是个size为0的map,
// 头节点指向当前传入的节点p,
// 此时,头节点head和尾节点tail都指向了当前传入的节点p
// 并且,此时head节点和tail节点,都没有自己的before和after节点
head = p;
else {
// 如果原先的尾节点不是null的话,
// 将当前传入的节点p的前一个节点before指向原先的尾节点last
p.before = last;
// 将原先的尾节点last的后一个节点after指向当前传入的节点p,
// 此时就构成了双向链表,last的after指向p,p的before指向last
// 此时,p的before就是head,head的after就是p,head的before为null,p的after也是null
last.after = p;
}
}
public V get(Object key) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return null;
if (accessOrder)
// 如果按照访问顺序排序的话
// 在node被访问后,走一下这个方法,给node排个序
afterNodeAccess(e);
return e.value;
}
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
// 将last指向原先的尾节点tail,
// last只被赋值了两次,
// 第一次是这里,last= tail,第二次是last = b
if (accessOrder && (last = tail) != e) {
// 如果按照访问顺序排序,并且原先的尾节点tail不等于最近访问的节点e,
// 如果原先的尾节点tail等于最近访问的节点e的话,就不用往下继续了,本来也是要把最近访问的节点放到最后的
// 将最近访问的节点e赋给节点p,p的before赋给节点b,p的after赋给节点a,
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
// 将p的after设置为null
p.after = null;
// 先判断b
if (b == null)
// 如果p的前一个节点b是null的话,说明p和head指向同一个节点,
// 访问完p之后,将p的后一个节点a设置为头节点,没毛病
head = a;
else
// 如果p的前一个节点不是null的话,
// 将p的前一个节点b的after指向p的后一个节点a
b.after = a;
// 再判断a
if (a != null)
// 如果p的后一个节点a不是null的话,说明p不是尾节点,
// 将a的before指向b,构成双向链表
a.before = b;
else
// 如果p的后一个节点a是null的话,说明p和tail指向同一个节点,
// 将last指向p的前一个节点,last不和tail指向同一个节点了,
// 第二次是这里,last = b
last = b;
if (last == null)
// 如果last等于null的话,
// 只能是last = b,而b本身是null,
// head,tail,p都是指向同一个节点,
// 所以head指向p
head = p;
else {
// 如果last不等于null的话,
// p的before指向last,也就是p的前节点指向原先的tail节点
p.before = last;
// 原先的尾节点tail的after指向p,构成双向链表
last.after = p;
}
// 无论上面怎么操作,新的tail肯定是指向了p,
// 也就是最近访问的节点,放到链表的最后
tail = p;
++modCount;
}
}
void afterNodeRemoval(Node<K,V> e) { // unlink
// 获取到移除的p节点和前驱b后继a节点
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
// 将p从链表中断开
p.before = p.after = null;
// 先判断b
if (b == null)
// 如果p的前一个节点b为null,说明p自己就是头节点
// 移除p之后,p的后继节点a就是头节点了,没毛病
head = a;
else
// 如果p的前驱节点b不是null,
// 将p的前驱节点的after指向p的后继节点a
b.after = a;
// 再判断a
if (a == null)
// 如果a为null的话,说明p为尾节点
// 移除p之后,p的前驱节点b和tail指向同一个节点
tail = b;
else
// 如果a不为null的话,说明p不是尾节点
// 将a的before指向p的前驱节点,构成双向链表
a.before = b;
}
以上是关于LinkedHashMa源码解析的主要内容,如果未能解决你的问题,请参考以下文章
片段(Java) | 机试题+算法思路+考点+代码解析 2023
Android 逆向类加载器 ClassLoader ( 类加载器源码简介 | BaseDexClassLoader | DexClassLoader | PathClassLoader )(代码片段
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段