zoukankan      html  css  js  c++  java
  • LinkedHashMap 的原理与源码解析

    LinkedHashMap 的原理与使用

    LinkedHashMap 是对 HashMap 的封装和拓展,在保留了 HashMap 原有功能的基础上,加了一些链表相关的属性,用来记录 HashMap 元素的先后顺序,这样如果要根据(节点插入或访问)顺序访问节点时,只要去遍历链表即可。

    默认元素插入顺序排序:

    @Test
    public void test1() {
        LinkedHashMap map = new LinkedHashMap();
        map.put("222", 222);
        map.put("111", 111);
        map.put("333", 333);
    
        System.out.println("遍历迭代器:");
        Iterator iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    
        System.out.println("遍历map:");
        map.forEach((k, v) -> {
            System.out.println(k + ": " + v);
        });
    
        /**
             * 执行结果:
             *
             * 遍历迭代器:
             * 222: 222
             * 111: 111
             * 333: 333
             * 遍历map:
             * 222: 222
             * 111: 111
             * 333: 333
             */
    }
    

    按照元素访问顺序排序:

    @Test
    public void test2() {
        LinkedHashMap map = new LinkedHashMap(4, 0.8f, true);
        map.put("222", 222);
        map.put("111", 111);
        map.put("333", 333);
    
        map.get("333");
        map.get("111");
        map.get("222");
    
        System.out.println("遍历迭代器:");
        Iterator iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    
        System.out.println("遍历map:");
        map.forEach((k, v) -> {
            System.out.println(k + ": " + v);
        });
    
        /**
             * 执行结果:
             * 
             * 遍历迭代器:
             * 333: 333
             * 111: 111
             * 222: 222
             * 遍历map:
             * 333: 333
             * 111: 111
             * 222: 222
             */
    }
    

    LinkedHashMap 源码解析

    内部类

    Entry
    static class Entry<K,V> extends HashMap.Node<K,V> {
        // before 指向此节点的前一个节点
        // after 指向此节点的后一个节点
        Entry<K,V> before, after;
        // Entry 构造方法,内部是调用了父类 HashMap 的构造方法
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }
    
    LinkedKeySet
    // LinkedHashMap 中所有节点元素的 key 集合
    final class LinkedKeySet extends AbstractSet<K> {
        public final int size()                 { return size; }
        public final void clear()               { LinkedHashMap.this.clear(); }
        // 获取 key 迭代器
        public final Iterator<K> iterator() {
            return new LinkedKeyIterator();
        }
        public final boolean contains(Object o) { return containsKey(o); }
        public final boolean remove(Object key) {
            return removeNode(hash(key), key, null, false, true) != null;
        }
        public final Spliterator<K> spliterator()  {
            return Spliterators.spliterator(this, Spliterator.SIZED |
                                            Spliterator.ORDERED |
                                            Spliterator.DISTINCT);
        }
        // 遍历所有 key
        public final void forEach(Consumer<? super K> 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);
            // 遍历时不能修改该 LinkedHashMap 对象
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }
    
    LinkedValues
    // LinkedHashMap 中所有节点元素的 value 集合
    final class LinkedValues extends AbstractCollection<V> {
        public final int size()                 { return size; }
        public final void clear()               { LinkedHashMap.this.clear(); }
        public final Iterator<V> iterator() {
            return new LinkedValueIterator();
        }
        public final boolean contains(Object o) { return containsValue(o); }
        public final Spliterator<V> spliterator() {
            return Spliterators.spliterator(this, Spliterator.SIZED |
                                            Spliterator.ORDERED);
        }
        // 遍历所有 value
        public final void forEach(Consumer<? 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.value);
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }
    
    LinkedEntrySet
    // LinkedHashMap 中所有节点元素的 entry 对象集合
    final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> {
        public final int size()                 { return size; }
        public final void clear()               { LinkedHashMap.this.clear(); }
        public final Iterator<Map.Entry<K,V>> iterator() {
            return new LinkedEntryIterator();
        }
        public final boolean contains(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?,?> e = (Map.Entry<?,?>) o;
            Object key = e.getKey();
            Node<K,V> candidate = getNode(hash(key), key);
            return candidate != null && candidate.equals(e);
        }
        public final boolean remove(Object o) {
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
                Object key = e.getKey();
                Object value = e.getValue();
                return removeNode(hash(key), key, value, true, true) != null;
            }
            return false;
        }
        public final Spliterator<Map.Entry<K,V>> spliterator() {
            return Spliterators.spliterator(this, Spliterator.SIZED |
                                            Spliterator.ORDERED |
                                            Spliterator.DISTINCT);
        }
        public final void forEach(Consumer<? super Map.Entry<K,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);
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }
    
    LinkedHashIterator
    // 迭代器
    abstract class LinkedHashIterator {
        LinkedHashMap.Entry<K,V> next;
        LinkedHashMap.Entry<K,V> current;
        int expectedModCount;
    
        LinkedHashIterator() {
            next = head;
            expectedModCount = modCount;
            current = null;
        }
    
        // 是否有下个节点
        public final boolean hasNext() {
            return next != null;
        }
    
        // 返回下一个节点
        final LinkedHashMap.Entry<K,V> nextNode() {
            LinkedHashMap.Entry<K,V> e = next;
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if (e == null)
                throw new NoSuchElementException();
            // 当前遍历到的节点
            current = e;
            // next 指向下一个要遍历的节点
            next = e.after;
            return e;
        }
    
        public final void remove() {
            Node<K,V> p = current;
            if (p == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            current = null;
            K key = p.key;
            removeNode(hash(key), key, null, false, false);
            expectedModCount = modCount;
        }
    }
    
    LinkedKeyIterator
    // key 迭代器
    final class LinkedKeyIterator extends LinkedHashIterator
        implements Iterator<K> {
        // 返回下一个节点的 key
        public final K next() { return nextNode().getKey(); }
    }
    
    LinkedValueIterator
    // value 迭代器
    final class LinkedValueIterator extends LinkedHashIterator
        implements Iterator<V> {
        // 返回下一个节点的 value 值
        public final V next() { return nextNode().value; }
    }
    
    LinkedEntryIterator
    // entry 迭代器
    final class LinkedEntryIterator extends LinkedHashIterator
        implements Iterator<Map.Entry<K,V>> {
        // 返回下一个节点的 entry 对象
        public final Map.Entry<K,V> next() { return nextNode(); }
    }
    

    属性

    // 双向链表的头结点
    transient LinkedHashMap.Entry<K,V> head;
    
    // 双向链表的尾结点
    transient LinkedHashMap.Entry<K,V> tail;
    
    // 链表节点的排序规则:
    // accessOrder 为 true,根据访问顺序排序
    // accessOrder 为 false,根据插入顺序排序
    final boolean accessOrder;
    

    构造方法

    // 默认是插入排序
    public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }
    
    // 默认是插入排序
    public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }
    
    // 默认是插入排序
    public LinkedHashMap() {
        super();
        accessOrder = false;
    }
    
    // 默认是插入排序
    public LinkedHashMap(Map<? extends K, ? extends V> m) {
        super();
        accessOrder = false;
        putMapEntries(m, false);
    }
    
    // 可以指定元素排序方式 accessOrder
    /**
         * Constructs an empty <tt>LinkedHashMap</tt> instance with the
         * specified initial capacity, load factor and ordering mode.
         *
         * @param  initialCapacity the initial capacity
         * @param  loadFactor      the load factor
         * @param  accessOrder     the ordering mode - <tt>true</tt> for
         *         access-order, <tt>false</tt> for insertion-order
         * @throws IllegalArgumentException if the initial capacity is negative
         *         or the load factor is nonpositive
         */
    public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }
    

    方法

    linkNodeLast
    // 将节点 p 插入到链表的尾部
    private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
        // 记录旧的尾结点
        LinkedHashMap.Entry<K,V> last = tail;
        // 更新 tail 指针,指向新插入的尾结点 p
        tail = p;
        // 如果插入前尾结点为 null,则表示链表当前无节点,
        // 则 head 结点也指向新插入的第一个节点 p
        if (last == null)
            head = p;
        else { // 链表不为空,直接将 p 插入到链表尾部
            p.before = last;
            last.after = p;
        }
    }
    
    // 用 dst 节点替换掉原来的 src 结点
    private void transferLinks(LinkedHashMap.Entry<K,V> src,
                               LinkedHashMap.Entry<K,V> dst) {
        // dst 的 before 指针指向 src 的 before 指针指向的节点
        LinkedHashMap.Entry<K,V> b = dst.before = src.before;
        // dst 的 after 指针指向 src 的 after 指针指向的节点
        LinkedHashMap.Entry<K,V> a = dst.after = src.after;
        
        // b 也指向 src.before
        // b 为 null,说明 src 是头结点,则现在 dst 也是头结点
        if (b == null)
            head = dst;
        else
            // 如果 src 不是头结点,则因为 dst 已经指向了 src.before
            // 所以现在只要将 src.before 指向的前序节点的 after 指针指向 dst 即可完成 dst 节点插入操作
            b.after = dst;
        
        // 同上
        if (a == null)
            tail = dst;
        else
            a.before = dst;
    }
    
    newNode
    // 插入一个 HashMap 的节点到链表尾部,并返回插入后的 LinkedHashMap 节点
    // LinkedHashMap 继承了 HashMap 类,在调用 put 方法时,会调用 newNode 方法
    // linkNodeLast 方法是按照元素插入顺序进行排序(将元素插入到链表尾部)
    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
    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
        LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
        // 使用 HashMap 节点 next 构造一个 LinkedHashMap 节点 t
        LinkedHashMap.Entry<K,V> t =
            new LinkedHashMap.Entry<K,V>(q.hash, q.key, q.value, next);
        // 然后用新构造的节点 t 替换原来的节点 p
        transferLinks(q, t);
        // 返回新构造的节点 t
        return t;
    }
    
    newTreeNode
    // 同 newNode 方法
    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<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
    // 删除节点 e
    void afterNodeRemoval(Node<K,V> e) { // unlink
        // 将 e 转成 LinkedHashMap  节点 p
        // b 指向 p 的 before 节点
        // a 指向 p 的 after 节点
        LinkedHashMap.Entry<K,V> p =
            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
        // 将 p.before 和 p.after 置空,即删除节点 p
        p.before = p.after = null;
        // 如果 b 为 null,表示 p 是链表第一个节点
        if (b == null)
            // 则 head 指向 p 的下一个节点(p.after)
            head = a;
        else
            // 如果 b(p.before)不为空
            // 则 p 的前序节点的(b) after 指针指向 p 的 after 节点(a)
            b.after = a;
        
        // 如果 a 为空,表示 p 是链表的最后一个节点
        if (a == null)
            // 则 p.before 节点 b 现在是链表的最后一个节点,则更新 tail 节点
            tail = b;
        else
            // 如果 a 不为空
            // 则 p 的后继节点的(a) before 指针指向 p 的 before 节点(b)
            a.before = b;
    }
    
    afterNodeInsertion
    // 节点插入 HashMap 后的钩子方法
    void afterNodeInsertion(boolean evict) { // possibly remove eldest
        LinkedHashMap.Entry<K,V> first;
        if (evict && (first = head) != null && removeEldestEntry(first)) {
            K key = first.key;
            removeNode(hash(key), key, null, false, true);
        }
    }
    
    afterNodeAccess
    // 访问了 HashMap 节点后的钩子方法
    void afterNodeAccess(Node<K,V> e) { // move node to last
        LinkedHashMap.Entry<K,V> last;
        // 如果 accessOrder 为 true
        // 并且 e 不为链表的尾结点
        // 则根据节点的访问顺序将节点排序,即将访问的节点 e 移动到链表的尾部
        if (accessOrder && (last = tail) != e) {
            // 将节点 e 转成 LinkedHashMap 节点 p
            LinkedHashMap.Entry<K,V> p =
                (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
            // 要将节点 p 移动到链表的尾部
            // 所以将 p.after 置空
            p.after = null;
            // 如果 b 为 null,则 p 原先为头结点
            if (b == null)
                // 现在要将 p 移动到链表尾部
                // 则 p 的后继节点 a 现在为头结点
                head = a;
            else
                // 如果 b 不为 null
                // 则将 p 的前序节点(b)的后继节点(b.after)指向 p 的后继节点(a)
                b.after = a;
            // 如果 a 不为空,则表示 p 不为尾结点
            if (a != null)
                // 则将 p 的后继节点(a)的前序节点(a.before)指向 p 的前序节点(b)
                a.before = b;
            else
                // 否则 p 为链表的尾结点
                // 使用 last 记录 p 的前序节点 b
                // (外层判断了 p 不能为尾节点)
                last = b;
            
            // 上面 last 记录了 p 的前序节点 b
            // 如果 b 为 null
            if (last == null)
                // 则链表中只有 p 这一个节点
                head = p;
            else { // 将 p 移到链表尾部
                p.before = last;
                last.after = p;
            }
            // 尾结点指向 p
            tail = p;
            ++modCount;
        }
    }
    
    containsValue
    // 判断链表节点中是否有值为 value 的
    public boolean containsValue(Object value) {
        // 从头结点开始遍历链表
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
            V v = e.value;
            // 如果链表节点元素值等于 value
            if (v == value || (value != null && value.equals(v)))
                // 则返回 true
                return true;
        }
        return false;
    }
    
    get
    // 根据 key 获取节点元素的值
    public V get(Object key) {
        Node<K,V> e;
        // 根据 key 找不到元素,则直接返回 null
        if ((e = getNode(hash(key), key)) == null)
            return null;
        // 根据 key 找到了元素,则判断是否根据访问顺序排序
        if (accessOrder)
            afterNodeAccess(e);
        return e.value;
    }
    
    getOrDefault
    // 根据 key 获取节点元素的值,如果获取不到,则返回默认值 defaultValue
    public V getOrDefault(Object key, V defaultValue) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) == null)
            return defaultValue;
        if (accessOrder)
            afterNodeAccess(e);
        return e.value;
    }
    
    keySet
    transient Set<K>        keySet;
    
    // 所有所有 key 的集合
    public Set<K> keySet() {
        // 获取 keySet
        Set<K> ks = keySet;
        // 如果 keySet 为空
        if (ks == null) {
            // 则构造一个 LinkedKeySet 对象
            ks = new LinkedKeySet();
            keySet = ks;
        }
        return ks;
    }
    
    values
    public Collection<V> values() {
        Collection<V> vs = values;
        if (vs == null) {
            vs = new LinkedValues();
            values = vs;
        }
        return vs;
    }
    
    entrySet
    public Set<Map.Entry<K,V>> entrySet() {
        Set<Map.Entry<K,V>> es;
        return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
    }
    
    forEach
    // 遍历
    public void forEach(BiConsumer<? super K, ? super V> action) {
        if (action == null)
            throw new NullPointerException();
        int mc = modCount;
        // 从 head 结点开始遍历节点
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
            action.accept(e.key, e.value);
        if (modCount != mc)
            throw new ConcurrentModificationException();
    }
    
    replaceAll
    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        if (function == null)
            throw new NullPointerException();
        int mc = modCount;
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
            e.value = function.apply(e.key, e.value);
        if (modCount != mc)
            throw new ConcurrentModificationException();
    }
    
  • 相关阅读:
    5-JVM常用的命令
    4-JVM 参数
    3-JVM垃圾回收算法和垃圾收集器
    2-JVM内存结构
    1-JVM基础
    非常短的git学习笔记
    白话马尔科夫链蒙特卡罗方法(MCMC)
    写了个小游戏,来玩
    胡小兔的 高考2019 游记
    机房志 | 一篇中二的文章
  • 原文地址:https://www.cnblogs.com/wu726/p/15734473.html
Copyright © 2011-2022 走看看