Map-LinkedHashMap源码笔记

3.LinkedHashMap

Map-LinkedHashMap源码笔记

LinkedHashMap是继承了HashMap,在维护HashMap的数组,链表,红黑树的基础上,加入了一个双向链表,让插入的数据,根据时间的先后,有了顺序。

transient LinkedHashMap.Entry<K,V> head;
transient LinkedHashMap.Entry<K,V> tail;

static class Entry<K,V> extends HashMap.Node<K,V> {
        Entry<K,V> before, after;
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
}

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

每当创建节点的时候,无论是树节点,还是链表节点,都会调用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;
    }

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

其他操作与hashMap一样

不同的是forEach方法

hashmap维护的数组是很大的,所以遍历起来就会很慢,而LinkedHashMap直接遍历节点,所以更快。

//LinkedHashMap的
public void forEach(BiConsumer<? super K, ? super V> action) {
        if (action == null)
            throw new NullPointerException();
        int mc = modCount;
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
            action.accept(e.key, e.value);
        if (modCount != mc)
            throw new ConcurrentModificationException();
    }
//hashMap的
 public void forEach(BiConsumer<? super K, ? super V> action) {
        Node<K,V>[] tab;
        if (action == null)
            throw new NullPointerException();
        if (size > 0 && (tab = table) != null) {
            int mc = modCount;
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next)
                    action.accept(e.key, e.value);
            }
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }

test

public static void main(String[] args) {
        LinkedHashMap<Integer,Integer> linkedHashMap = new LinkedHashMap<>();
        for(int i = 0 ; i < 10; i++){
            linkedHashMap.put(i,i);
        }
        long start = System.nanoTime();
        linkedHashMap.forEach((K,V)->{System.out.print(V);});
        long end = System.nanoTime();
        System.out.println();
        System.out.println(end - start);
        HashMap<Integer,Integer> hm = new HashMap<>();
        for(int i = 0 ; i < 10; i++){
            hm.put(i,i);
        }
        System.out.println();
        start = System.nanoTime();
        hm.forEach((K,V)->{System.out.print(V);});
        end = System.nanoTime();
        System.out.println();
        System.out.println(end - start);
    }

结果

0123456789
55960500

0123456789
476600

总结,相比于HashMap,LinkedHashMap在增删的上会慢,但是在遍历上有优势。因为LinkedHashMap的get方法是调用了HashMap的方法,所以get方法的速率应该是一样的。

上一篇:LruCache里为什么用LinkedHashMap,HashMap可以吗?


下一篇:js如何在外部改变React受控组件的状态量?