LinkedHashMap源码解析

/*
 * LinkedHashMap的底层结构一直有个困惑纠结了好久
 * 它继承自HashMap,HashMap底层结构是哈希表+单链表的组合
 * LinkedHashMap为了保存其数据,加入了双向循环链表来存放数据,双向链表和哈希+单向链表如何组合的呢?
 * 这个问题想了很久,最后发现他们一点关系都没有!!只是Entry中既可以保存单链表指针next,也可以保存双链表
 * 指针after,before,然后增加header,双联表的数据结构是单独存在的。。。
 * 
 * LinkedHashMap继承自HashMap,增加了新的特性:
 * 对存储的数据保存其存储顺序,可以根据最近使用的元素进行排序
 */
public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>
{

    //序列化
    private static final long serialVersionUID = 3801124242820219131L;

    //双向链表head,Header中不存储数据
    private transient Entry<K,V> header;

    /**
     * The iteration ordering method for this linked hash map: <tt>true</tt>
     * for access-order, <tt>false</tt> for insertion-order.
     *
     * @serial
     */
    private final boolean accessOrder;

    /**
     * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
     * with the specified initial capacity and load factor.
     *
     * @param  initialCapacity the initial capacity
     * @param  loadFactor      the load factor
     * @throws IllegalArgumentException if the initial capacity is negative
     *         or the load factor is nonpositive
     */
    public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }

    /**
     * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
     * with the specified initial capacity and a default load factor (0.75).
     *
     * @param  initialCapacity the initial capacity
     * @throws IllegalArgumentException if the initial capacity is negative
     */
    public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }

    /**
     * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
     * with the default initial capacity (16) and load factor (0.75).
     */
    public LinkedHashMap() {
        super();
        accessOrder = false;
    }

    /**
     * Constructs an insertion-ordered <tt>LinkedHashMap</tt> instance with
     * the same mappings as the specified map.  The <tt>LinkedHashMap</tt>
     * instance is created with a default load factor (0.75) and an initial
     * capacity sufficient to hold the mappings in the specified map.
     *
     * @param  m the map whose mappings are to be placed in this map
     * @throws NullPointerException if the specified map is null
     */
    public LinkedHashMap(Map<? extends K, ? extends V> m) {
        super(m);
        accessOrder = false;
    }

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

    /**
     * HashMap中留的hook,构造器执行,添加元素前执行
     */
    @Override
    void init() {
        header = new Entry<>(-1, null, null, null);
        //初始化双向链表节点
        header.before = header.after = header;
    }

    /**
     * Transfers all entries to new table array.  This method is called
     * by superclass resize.  It is overridden for performance, as it is
     * faster to iterate using our linked list.
     * 将Entrys转移到newTable中,转移时,以双链表的顺序逐个进行
     */
    @Override
    void transfer(HashMap.Entry[] newTable, boolean rehash) {
        int newCapacity = newTable.length;
        //从header开始遍历向后遍历
        //e=header时,遍历结束
        for (Entry<K,V> e = header.after; e != header; e = e.after) {
            if (rehash)
                //获取hash值
                e.hash = (e.key == null) ? 0 : hash(e.key);
            //获取index值
            int index = indexFor(e.hash, newCapacity);
            e.next = newTable[index];
            newTable[index] = e;
        }
    }


    /**
     * 以双链表的顺序进行遍历
     */
    public boolean containsValue(Object value) {
        // Overridden to take advantage of faster iterator
        if (value==null) {
            for (Entry e = header.after; e != header; e = e.after)
                if (e.value==null)
                    return true;
        } else {
            for (Entry e = header.after; e != header; e = e.after)
                if (value.equals(e.value))
                    return true;
        }
        return false;
    }

    /**
     * 覆盖HashMap中的get(),改变链表的顺序
     */
    public V get(Object key) {
        Entry<K,V> e = (Entry<K,V>)getEntry(key);
        if (e == null)
            return null;
        //改变链表顺序
        e.recordAccess(this);
        return e.value;
    }

    /**
     * Removes all of the mappings from this map.
     * The map will be empty after this call returns.
     */
    public void clear() {
        //将每个单链表的first元素清空
        super.clear();
        //将header元素清空
        header.before = header.after = header;
    }

    /**
     * LinkedHashMap entry.
     */
    private static class Entry<K,V> extends HashMap.Entry<K,V> {
        // These fields comprise the doubly linked list used for iteration.
        Entry<K,V> before, after;
        //继承自HashMap.Entry的元素:next,hash,key,value

        //初始化时,没有给before,after赋值,那它们在哪赋值的呢?
        //我们会发现header为null时,after=before=header
        //header不为null时,after和befor的值在addBefore时赋值
        Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
            super(hash, key, value, next);
        }

        /**
         * 回收交给GC
         * 双向链表remove两个指针改动
         * 1.上一个节点的after设为下一个节点
         * 2。下一个节点的befor设为上一个节点
         */
        private void remove() {
            //before。after = after
            before.after = after;
            //after.before = before
            after.before = before;
        }

        /**
         * 将this插入至existingEntry之前
         * 在双向链表中插入元素需要做4个指针的改动
         * 1.将this的上一个节点设为e的上一个节点
         * 2.将this的下一个节点设为e
         * 3.将上一个节点的after设为this
         * 4。将e的上一个节点设为this
         */
        private void addBefore(Entry<K,V> existingEntry) {
//          this.before = existingEntry.before;
//          this.after = existingEntry;
//          existingEntry.before.after=this;
//          existingEntry.before = this;

            //2.将this的下一个节点设为e
            after  = existingEntry;
            //1.将this的上一个节点设为e的上一个节点
            before = existingEntry.before;
            //3.将上一个节点的after设为this
            before.after = this;
            //4。将e的上一个节点设为this
            after.before = this;
        }

        /**
         * put和set后执行此方法,
         * 作用是改变元素在链表中的顺序,实现按照 最近访问的顺序排列的功能
         */
        void recordAccess(HashMap<K,V> m) {
            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
            //以最近访问的顺序排列时,执行操作
            if (lm.accessOrder) {
                lm.modCount++;
                //LinkedHashMap每次插入元素时,如果远来存在数据则替换数据,替换后的顺序不是我们想要的顺序
                //所以删除此元素,然后重新添加,执行addBefore
                //同样的道理,执行get获得元素后,元素的存储位置也不是我们想要的顺序
                remove();
                addBefore(lm.header);
            }
        }

        //hashMap中的remove值消除掉了Next指针,在这里消除befor,after的关联
        void recordRemoval(HashMap<K,V> m) {
            remove();
        }
    }

    private abstract class LinkedHashIterator<T> implements Iterator<T> {
        Entry<K,V> nextEntry    = header.after;
        Entry<K,V> lastReturned = null;

        /**
         * The modCount value that the iterator believes that the backing
         * List should have.  If this expectation is violated, the iterator
         * has detected concurrent modification.
         */
        int expectedModCount = modCount;

        public boolean hasNext() {
            return nextEntry != header;
        }

        public void remove() {
            if (lastReturned == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();

            LinkedHashMap.this.remove(lastReturned.key);
            lastReturned = null;
            expectedModCount = modCount;
        }

        Entry<K,V> nextEntry() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if (nextEntry == header)
                throw new NoSuchElementException();

            Entry<K,V> e = lastReturned = nextEntry;
            nextEntry = e.after;
            return e;
        }
    }

    private class KeyIterator extends LinkedHashIterator<K> {
        public K next() { return nextEntry().getKey(); }
    }

    private class ValueIterator extends LinkedHashIterator<V> {
        public V next() { return nextEntry().value; }
    }

    private class EntryIterator extends LinkedHashIterator<Map.Entry<K,V>> {
        public Map.Entry<K,V> next() { return nextEntry(); }
    }

    // These Overrides alter the behavior of superclass view iterator() methods
    Iterator<K> newKeyIterator()   { return new KeyIterator();   }
    Iterator<V> newValueIterator() { return new ValueIterator(); }
    Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); }

    void addEntry(int hash, K key, V value, int bucketIndex) {
        super.addEntry(hash, key, value, bucketIndex);

        // Remove eldest entry if instructed
        Entry<K,V> eldest = header.after;
        if (removeEldestEntry(eldest)) {
            removeEntryForKey(eldest.key);
        }
    }

    /**
     * This override differs from addEntry in that it doesn't resize the
     * table or remove the eldest entry.
     */
    void createEntry(int hash, K key, V value, int bucketIndex) {
        HashMap.Entry<K,V> old = table[bucketIndex];
        Entry<K,V> e = new Entry<>(hash, key, value, old);
        table[bucketIndex] = e;
        e.addBefore(header);
        size++;
    }

    /**
     * 如果此映射移除其最旧的条目,则返回 true.此时容量put容量不再改变
     */
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值