美文网首页
LinkedHashMap源码浅析(二):访问顺序

LinkedHashMap源码浅析(二):访问顺序

作者: 小川君 | 来源:发表于2018-09-16 00:09 被阅读0次

前面我们有说LinkedHashMap的顺序有两种,一种是插入顺序,这也是默认的顺序,因为LinkedHashMap的内部维护着一个双链表,元素的插入每次只需插入到尾节点即可,遍历的时候,从头结点开始,就可按照插入顺序遍历到链表尾部;还有一种顺序是访问排序,设置访问顺序的标识是final boolean accessOrder,设置此属性的值为true即可按照访问的顺序对数据进行排序,每次访问一个元素之后,会将该元素置于链表的尾节点

put

我们首先来说put()中涉及到的访问顺序的操作,在HashMapputVal()中有这样的一段代码
HashMap#putVal():

            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }

可以看到,在添加元素的时候,发现该key值上有元素值,除了覆盖原始值之外,还调用了afterNodeAccess(),而这个方法在HashMap中是空实现,具体的实现在LinkedHashMap
LinkedHashMap#afterNodeAccess():

    void afterNodeAccess(Node<K,V> e) { // move node to last
        LinkedHashMapEntry<K,V> last;
        if (accessOrder && (last = tail) != e) {
            LinkedHashMapEntry<K,V> p =
                (LinkedHashMapEntry<K,V>)e, b = p.before, a = p.after;
            p.after = null;
            if (b == null)
                head = a;
            else
                b.after = a;
            if (a != null)
                a.before = b;
            else
                last = b;
            if (last == null)
                head = p;
            else {
                p.before = last;
                last.after = p;
            }
            tail = p;
            ++modCount;
        }
    }

首先看这个判断条件,accessOrder = true且新增节点e不能为尾节点,正好符合HashMap的处理,进入判断体,我们可以看到,首先获取到新增节点的前后节点指针引用(前指针引用下面简称为b,后指针引用下面简称a),将当前节点后一节点的指针设为空,
然后判断此节点的是不是头结点,如果是头结点则将此节点的后一节点a设置为头结点,如果不是,则将b的后一节点指针指向a
如果当前节点不是尾节点(这个是肯定的,前面判断过了)则将a的前一节点指针指向b,
上面两步将节点e脱离了链表出来,下面则会将e添加到链表头部
首先会判断下last是否为空,last的赋值在上面,默认为尾节点并且不会为空,所以这里会走else,首先将当前节点的前一节点的指针指向原先的尾节点,然后将尾节点的下一节点指针指向当前节点,那么当前节点则变成了尾节点,最后将当前节点赋值给尾节点tail
如此便按照访问顺序修改了集合中链表的元素顺序。

get

LinkedHashMap#get():

    public V get(Object key) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) == null)
            return null;
        if (accessOrder)
            afterNodeAccess(e);
        return e.value;
    }

这里也是调用了afterNodeAccess方法 不在多说

相关文章

网友评论

      本文标题:LinkedHashMap源码浅析(二):访问顺序

      本文链接:https://www.haomeiwen.com/subject/ukajgftx.html