码迷,mamicode.com
首页 > 其他好文 > 详细

LinkedHashMap类源码解析

时间:2016-07-17 16:51:03      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:

LinkedHashMap
1.通过链表实现存储,可以根据插入顺序遍历数组
2.hashcode计算方法和HashMap的一样

继承HashMap
实现Map

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>

成员变量


    private static final long serialVersionUID = 3801124242820219131L;

    /**
     * 双链表的头结点
     */
    private transient Entry<K,V> header;

    /**
     * 遍历的顺序 对于访问顺序,为true;对于插入顺序,则为false(默认)
     * true for access-order, <tt>false</tt> for insertion-order.
     *
     * @serial
     */
    private final boolean accessOrder;

构造函数


    /**
     * 构造函数
     *
     * @param  initialCapacity 初始容量
     * @param  loadFactor      装载因子
     * @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;
    }

    /**
     * 装载因子0.75的构造函数
     * @param  initialCapacity 初始容量
     * @throws IllegalArgumentException if the initial capacity is negative
     */
    public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }

    /**
     * 构造函数  
     *default initial capacity (16) and load factor (0.75).
     */
    public LinkedHashMap() {
        super();
        accessOrder = false;
    }

    /**
     * 构造函数:m集合元素加入到当前map中
     *  default load factor (0.75) 
     * @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;
    }

    /**
     * 构造函数 
     * @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;
    }

结点定义结构

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

        Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
            super(hash, key, value, next);
        }

        /**
         * remove
         */
        private void remove() {
            before.after = after;
            after.before = before;
        }

        /**
         * addBefore
         */
        private void addBefore(Entry<K,V> existingEntry) {
            after  = existingEntry;
            before = existingEntry.before;
            before.after = this;
            after.before = this;
        }

        /**
         * This method is invoked by the superclass whenever the value
         * of a pre-existing entry is read by Map.get or modified by Map.set.
         * If the enclosing Map is access-ordered, it moves the entry
         * to the end of the list; otherwise, it does nothing.
         */
        void recordAccess(HashMap<K,V> m) {
            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
            if (lm.accessOrder) {
                lm.modCount++;
                remove();
                addBefore(lm.header);
            }
        }

        void recordRemoval(HashMap<K,V> m) {
            remove();
        }
    }

双链表的初始化


    /**
     * 初始化,可以看出有一个头指针
     */
    @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.
     */
    @Override
    void transfer(HashMap.Entry[] newTable, boolean rehash) {
        int newCapacity = newTable.length;
        for (Entry<K,V> e = header.after; e != header; e = e.after) {
            if (rehash)
                e.hash = (e.key == null) ? 0 : hash(e.key);
            int index = indexFor(e.hash, newCapacity);
            e.next = newTable[index];
            newTable[index] = e;
        }
    }

containsValue
直接根据双链表进行顺序遍历、
重写了HashMap的containsValue,效率提高


    /**
     * containsValue
     * @param value value whose presence in this map is to be tested
     * @return <tt>true</tt> if this map maps one or more keys to the
     *         specified value
     */
    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;
    }

没有实现containsKey方法
HashMap中是根据key计算hashcode,找到对应的table[i],在顺序查找,现在这个查找效率比较高,毕竟只遍历了部分数据。

clear

    /**
     * clear
     */
    public void clear() {
        super.clear();
        header.before = header.after = header;
    }

get
getEntry 方法是调用父类,其程序原理和containsKey方法一样,在HashMap中containsKey方法调用的getEntry方法。

    /**
     * V get(Object key)
     */
    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;
    }

LinkedHashMap没有实现put方法,其重写了HashMap.put里面的recordAccess、addEntry方法
HashMap.put

    public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key); // 计算hash值 
        int i = indexFor(hash, table.length); // 转化为所在数组的下标 
        for (Entry<K,V> e = table[i]; e != null; e = e.next) { // 顺序遍历所在链表,判断是否已经存在
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value; // key已经存在,新的value 更新老的value 
                e.recordAccess(this); 
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i); // 不存在时候  插入该新的节点 
        return null;
    }

LinkedHashMap重写recordAccess、addEntry方法


    /**
     * 重写HashMap的方法,
     * This override alters behavior of superclass put method. It causes newly
     * allocated entry to get inserted at the end of the linked list and
     * removes the eldest entry if appropriate.
     */
    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); // 新结点 e 
        table[bucketIndex] = e; // table 中加入结点 e 
        e.addBefore(header); // 加入到头部 
        size++;
    }

    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }
}

可以看出,表面上LinkedHashMap通过双链表作为存储结构,其实双链表只是记录结点的插入顺序,方便了对LinkedHashMap中结点的遍历,其父类的table同样作为存储结构,table的存在是使得相同的hashcode的结点将会存储在同一个table[i]桶内。符合Map的定义,如果没有table数组,直接双链表存储,没有必要计算hashcode,与LinkedList几乎意义一样。 table数组的存在,在get方法和containsKey方法中用到,LinkedHashMap没有重写containsKey方法,上面有讲解。

迭代器

    // 根据插入顺序的迭代器 
    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;
        }
    }
    // KeyIterator 
    private class KeyIterator extends LinkedHashIterator<K> {
        public K next() { return nextEntry().getKey(); }
    }
    // ValueIterator
    private class ValueIterator extends LinkedHashIterator<V> {
        public V next() { return nextEntry().value; }
    }
    // EntryIterator
    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(); }

LinkedHashMap类源码解析

标签:

原文地址:http://blog.csdn.net/qunxingvip/article/details/51931508

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!