当前位置: 移动技术网 > IT编程>开发语言>Java > LinkedHashMap源码学习

LinkedHashMap源码学习

2019年11月21日  | 移动技术网IT编程  | 我要评论
描述 可以按照添 加元素的顺序 对元素进行迭代的 的子类. 注意,上面说的是 加元素的顺序 .也就是说, 更新元素 时,是不会影响遍历结构的的.除非设置参数 为`true`,将更新元素放置到 队末 . 这个类没有对其父类 进行过多重写.主要通过实现 相关方法,在数据结构变更后,进行后置的 结构更新进 ...

描述

  • 可以按照添加元素的顺序对元素进行迭代的hashmap的子类.
  • 注意,上面说的是加元素的顺序.也就是说,更新元素时,是不会影响遍历结构的的.除非设置参数accessordertrue,将更新元素放置到队末.
  • 这个类没有对其父类hashmap进行过多重写.主要通过实现afternode*相关方法,在数据结构变更后,进行后置的链表结构更新进行维护.

常用与关键方法

linknodelast方法

描述:

  • 负责初始化成员变量headtail.
  • headtail初始化完成后,负责将目标元素p连接到tail并更新原有tail到目标元素p

代码:

private void linknodelast(linkedhashmap.entry<k,v> p) {
    // 缓存尾部
    linkedhashmap.entry<k,v> last = tail;
    // 更新尾部到新元素
    tail = p;
    // 判断老尾部是否已经初始化
    if (last == null)
        // 老尾部为初始化,代表头部也没初始化.进行初始化操作
        head = p;
    else {
        // 初始化以完成,将p链接到老尾部之后
        p.before = last;
        last.after = p;
    }
}

transferlinks方法

描述:

使用dst替换src在双向链表中的位置

代码:

private void transferlinks(linkedhashmap.entry<k,v> src,
                           linkedhashmap.entry<k,v> dst) {
    // 同步before,同时保存到局部变量
    linkedhashmap.entry<k,v> b = dst.before = src.before;
    // 同步after,同时保存到局部变量
    linkedhashmap.entry<k,v> a = dst.after = src.after;
    // 检查before
    if (b == null)
        // 没有before.将dst设置为head节点
        head = dst;
    else
        // 有before,将before与dst关联
        b.after = dst;
    // 检查after
    if (a == null)
        // 没有after,将dst作为tail节点
        tail = dst;
    else
        // 有after,将after与dst连接
        a.before = dst;
}

newnode方法

描述:

重写了父类newnode方法.扩展双向链表的连接操作.返回了hashmap.node的子类节点linkedhashmap.entry.

代码:

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;
}

replacementnode方法

描述:

扩展双向链表替换节点的操作.这个方法用于父类hashmaphashmap.treenode替换为hashmap.node时调用,这里进行了重写,使用带有双向链表的linkedhashmap.entry作为返回值
注意: 这里hashmap.treenode是实现了linkedhashmap.entry的.也就是参数p,他可以直接强转为实现类linkedhashmap.entry

代码:

node<k,v> replacementnode(node<k,v> p, node<k,v> next) {
    linkedhashmap.entry<k,v> q = (linkedhashmap.entry<k,v>)p;
    linkedhashmap.entry<k,v> t =
        new linkedhashmap.entry<k,v>(q.hash, q.key, q.value, next);
    // 替换节点
    transferlinks(q, t);
    return t;
}

newtreenode方法

描述:

重写了父类方法newtreenode.扩展双向链表的连接操作.同样,因为hashmap.treenode实现linkedhashmap.entry.可以直接通过linknodelast方法进行连接操作

代码:

treenode<k,v> newtreenode(int hash, k key, v value, node<k,v> next) {
    treenode<k,v> p = new treenode<k,v>(hash, key, value, next);
    linknodelast(p);
    return p;
}

replacementtreenode方法

描述:

replacementnode.扩展双向链表替换节点的操作.只是节点类型变成了treenode.又因为他是linkedhashmap.entry的子类,可以直接交给transferlinks使用.进行双向链表替换操作

代码:

treenode<k,v> replacementtreenode(node<k,v> p, node<k,v> next) {
    linkedhashmap.entry<k,v> q = (linkedhashmap.entry<k,v>)p;
    treenode<k,v> t = new treenode<k,v>(q.hash, q.key, q.value, next);
    transferlinks(q, t);
    return t;
}

afternoderemoval方法

描述:

删除节点后调用.进行双向链表同步

代码:

void afternoderemoval(node<k,v> e) { // unlink
    // b - before节点
    // p - 被删除节点
    // a - after节点
    linkedhashmap.entry<k,v> p =
        (linkedhashmap.entry<k,v>)e, b = p.before, a = p.after;
    // 清除p的双端引用
    p.before = p.after = null;
    
    // 判断before是否存在
    if (b == null)
        // 没有before
        // 设置a为head
        head = a;
    else
        // 存在before
        // 连接b->a.注意,这是单向连接,现在还无法确认a是否存在.如果a为空,b就是链表中的唯一节点.after属性为null
        b.after = a;
    // 判断a是否为空
    if (a == null)
        // a为空
        // tail设置为b
        tail = b;
    else
        // a存在
        // 连接 a->b.注意,这里也是单向连接.如果b是空的话,a现在就是head且before属性是null
        a.before = b;
}

afternodeaccess方法

描述:

更新节点后调用.进行双向链表同步

代码:

void afternodeaccess(node<k,v> e) { // move node to last
    // oldtail.老尾部缓存
    linkedhashmap.entry<k,v> last;
    // 判断accessorder.即按照访问(更新)顺序排列
    // 获取老尾部
    // 判断当前元素是不是尾部元素
    if (accessorder && (last = tail) != e) {
        // accessorder==true且e不要尾部元素
        
        // b - fefore
        // p - 当前元素
        // a - after
        linkedhashmap.entry<k,v> p =
            (linkedhashmap.entry<k,v>)e, b = p.before, a = p.after;
        
        // 因为p将变为尾部元素,所以直接设置p.after为null.
        p.after = null;
        
        // 判断b
        if (b == null)
            // b为null,p节点就是head节点
            // a作为头部节点
            head = a;
        else
            // b不为空
            // 连接b->a. 注意,这里是单向连接.a可能为null,a.before的连接交给后续判断
            b.after = a;
        
        // 判断a
        if (a != null)
            // a不为空
            // a->b.注意,这里是单向链接.b可能是null.b.after的连接交给后续判断
            a.before = b;
        else
            // a为空.p节点就是tail节点
            // 这里有两个分支,需要判断b是否为空.此处a已经为空,如果b也为空,说明p是列表中的唯一节点.这个判断委托到后续判断中处理
            // 此时,last变量已经失去意义,它与p为同一对象.
            // 这里说一下赋值last = b;的作用.注意,这是本人猜测!
            // 是为了统一算法的外在样式.因为变量last在在本方法中是不会为空的,且在所有的情形中,都会调用p.before = last;last.after = p;进行连接(除了p是唯一元素的情况).
            // 那么在b存在的时候,再次与p进行连接,在链表结构上也是没有问题的,统一被视作被操作元素的前一个元素
            last = b;
        if (last == null)
            // p是唯一元素
            head = p;
        else {
            // 连接到尾部节点
            p.before = last;
            last.after = p;
        }
        // 更新尾部节点到p
        tail = p;
        // 修改计数++
        ++modcount;
    }
}

内部类

linkedhashiterator

描述:

封装了针对链表结构的迭代器.并向子类提供了共有的扩展方法.

代码:

abstract class linkedhashiterator {
    linkedhashmap.entry<k,v> next;
    linkedhashmap.entry<k,v> current;
    int expectedmodcount;

    linkedhashiterator() {
        // 初始化next节点为当前head
        next = head;
        expectedmodcount = modcount;
        current = null;
    }

    public final boolean hasnext() {
        return next != null;
    }

    final linkedhashmap.entry<k,v> nextnode() {
        // 缓存next
        linkedhashmap.entry<k,v> e = next;
        // fast-fail
        if (modcount != expectedmodcount)
            throw new concurrentmodificationexception();
        // next为空
        if (e == null)
            throw new nosuchelementexception();
        // 设置当前
        current = e;
        // 更新next到下一个
        next = e.after;
        return e;
    }

    public final void remove() {
        // 获取当前
        node<k,v> p = current;
        // null判断
        if (p == null)
            throw new illegalstateexception();
        // fast-fail
        if (modcount != expectedmodcount)
            throw new concurrentmodificationexception();
        // 迭代器置空
        current = null;
        // 获取key
        k key = p.key;
        // 调用父类的removenode方法进行节点删除
        removenode(hash(key), key, null, false, false);
        // 同步更新计数
        expectedmodcount = modcount;
    }
}

内部类

linkedhashiterator实现

描述:

分别继承了linkedhashiterator并使用前者的nextnode方法返回不同数据

代码:

final class linkedkeyiterator extends linkedhashiterator
    implements iterator<k> {
    public final k next() { return nextnode().getkey(); }
}

final class linkedvalueiterator extends linkedhashiterator
    implements iterator<v> {
    public final v next() { return nextnode().value; }
}

final class linkedentryiterator extends linkedhashiterator
    implements iterator<map.entry<k,v>> {
    public final map.entry<k,v> next() { return nextnode(); }
}

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网