LinkedHashMap类源码解析

来源:互联网 发布:newsql数据库哪个最好 编辑:程序博客网 时间:2024/05/16 11:43

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(); }
1 0
原创粉丝点击