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 )(代码片段

无法解析片段中的 findViewById [重复]

C# 获得目录创建时间的源码片段

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段