LinkedHashMap源码分析,基于jdk1.8,附源码

LinkedHashMap 其继承了HashMap,提供了顺序保存,是通过对(键 值对)维护一个双向链表来实现的。
其提供的内部排序分为两种:访问顺序排序(ture)和 存储顺序排序(false),是通过布尔型变量accessOrder控制的;默认为false;

1.构造函数介绍

与HashMap类似,有疑问可看博主 关于HashMap源码介绍
源码:

/**
     * 与HashMap初始化类似
     */
    public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }

    /**
     *与HashMap初始化类似
     */
    public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }

    /**
     *与HashMap初始化类似
     */
    public LinkedHashMap() {
        super();
        accessOrder = false;
    }

    /**
     *与HashMap初始化类似
     */
    public LinkedHashMap(Map<? extends K, ? extends V> m) {
        super();
        accessOrder = false;
		//HashMap中的方法
        putMapEntries(m, false);
    }

    /**
     *与HashMap初始化类似
     * @param  initialCapacity map容量
     * @param  loadFactor 负载系数
     * @param  accessOrder  内部排序方式: 访问顺序排序(ture) ; 存储顺序排序(false)
     */
    public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

2.存入-put,获取-get、getOrDefault 删除-remove

其中put方法是调用HashMap中的,
get和remove是重写的HashMap方法
重要的是是重写了一些回调方法afterNodeAccess、afterNodeInsertion
(1)afterNodeAccess(Node<K,V> e) :将新更新的节点放在双向链表最后,若 accessOrder=true时还会将访问过得数据放在链表末尾
(2)afterNodeInsertion(boolean evict):是用与插入新元素是否需要删除头部元素,一般不会删除,只有重写其内部的方法removeEldestEntry(Map.Entry<K,V> eldest)才会实现删除,并且参数evict=true

源码:

/**
	 * 是用与插入新元素是否需要删除头部元素,一般不会删除,
	 * 只有重写其内部的方法removeEldestEntry(Map.Entry<K,V> eldest)才会实现删除,并且参数evict=true
	*/
    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);
        }
    }
	/**
	 * put使用存在的key和get使用
	 * 将新更新的节点放在双向链表最后
	 * 全局变量 head(存储链表头部),tail (存储链表尾部)
	*/
    void afterNodeAccess(Node<K,V> e) { 
		//临时存储尾部
        LinkedHashMap.Entry<K,V> last;
		//LinkedHashMap设置了操作排序,并且e不是尾部节点
        if (accessOrder && (last = tail) != e) {
			//用p存储当前节点e, b存储p(e)的上一个节点,a存储p(e)的下一个节点
            LinkedHashMap.Entry<K,V> p =
                (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
			//令p的下一个节点指向null(尾部节点的after一定的是null,头部节点的before为null)
            p.after = null;
			//b==null 标识p(e)的上一个节点为null,也就是p为 头部节点的before为null);
			//需要将p下一个节点设置为头结点
            if (b == null)
                head = a;
			//b!=null 标识p(e)的上一个节点存在值,也就是p不为头部节点的before为null);
			//需要将p的上一个节点指向p的下一个节点(此处注意p的下一个节点并没有指向p的上一个节点)
            else
                b.after = a;
			
			//a != null p的下一个节点不是空,也就是p不是尾部;
			//那么将a(p下一个节点)的上一个节点指向 b(p的上一个节点)
            if (a != null)
                a.before = b;
			//a == null a(p的下一个节点)为空,也就是p是尾部;
			//last 的引用指向b(p的上一个节点)的
            else
                last = b;
			
			//如果 last == null ,头部为p
            if (last == null)
                head = p;
			//如果 last != null ,p的上一个节点指向last,last的下一个节点指向p
            else {
                p.before = last;
                last.after = p;
            }
			//尾部指向新加的节点p
            tail = p;
            ++modCount;
        }
    }

3.删除Node节点回调

删除节点后会维护链表,维护其头尾部变化。
源码:

//删除node
	//全局变量 head(存储链表头部),tail (存储链表尾部)
    void afterNodeRemoval(Node<K,V> e) { // unlink
		//用p存储当前节点e, b存储p(e)的上一个节点,a存储p(e)的下一个节点
        LinkedHashMap.Entry<K,V> p =
            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
		//令p的下一个节点指向null,p的上一个节点指向null,执行完此方法,a/b/p 没有引用gc会回收
        p.before = p.after = null;
		//b==null 标识p(e)的上一个节点为null,也就是p为 头部节点的before为null);
		//需要将p下一个节点设置为头结点
        if (b == null)
            head = a;
		//b!=null 标识p(e)的上一个节点存在值,也就是p不为头部节点的before为null);
		//需要将p的上一个节点指向p的下一个节点(此处注意p的下一个节点并没有指向p的上一个节点)
        else
            b.after = a;
		
		//a == null a(p的下一个节点)为空,也就是p是尾部;
		//tail 的引用指向b(p的上一个节点)的
        if (a == null)
            tail = b;
		//a != null p的下一个节点不是空,也就是p不是尾部;
		//那么将a(p下一个节点)的上一个节点指向 b(p的上一个节点)
        else
            a.before = b;
    }

5.全部源码如下

/*
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.util;

import java.util.function.Consumer;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.io.IOException;


public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>
{
    /**
     * HashMap.Node subclass for normal LinkedHashMap entries.
     */
    static class Entry<K,V> extends HashMap.Node<K,V> {
		//before:上一个节点引用 after:下一个节点引用
        Entry<K,V> before, after;
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }

    private static final long serialVersionUID = 3801124242820219131L;

    /**
     * 保存头结点引用
     */
    transient LinkedHashMap.Entry<K,V> head;

    /**
     * 保存尾结点引用
     */
    transient LinkedHashMap.Entry<K,V> tail;

    /**
     * ture:访问顺序排序
     *false:存储顺序排序
     * @serial
     */
    final boolean accessOrder;

    // internal utilities

    // 将节点放在末尾
    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;
        }
    }

    // 具体Node和treeNode节点替换的实现
    private void transferLinks(LinkedHashMap.Entry<K,V> src,
                               LinkedHashMap.Entry<K,V> dst) {
        LinkedHashMap.Entry<K,V> b = dst.before = src.before;
        LinkedHashMap.Entry<K,V> a = dst.after = src.after;
        if (b == null)
            head = dst;
        else
            b.after = dst;
        if (a == null)
            tail = dst;
        else
            a.before = dst;
    }

    // HashMap钩子方法的重写
    void reinitialize() {
        super.reinitialize();
        head = tail = null;
    }
	//创建新的节点,将新节点放在双向链表结尾
    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;
    }
	//普通Node节点替换方法
    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
        LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
        LinkedHashMap.Entry<K,V> t =
            new LinkedHashMap.Entry<K,V>(q.hash, q.key, q.value, next);
        transferLinks(q, t);
        return t;
    }
	//创建新的树节点
    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;
    }
	//树节点替换方法
    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;
    }
	//删除node
	//全局变量 head(存储链表头部),tail (存储链表尾部)
    void afterNodeRemoval(Node<K,V> e) { // unlink
		//用p存储当前节点e, b存储p(e)的上一个节点,a存储p(e)的下一个节点
        LinkedHashMap.Entry<K,V> p =
            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
		//令p的下一个节点指向null,p的上一个节点指向null,执行完此方法,a/b/p 没有引用gc会回收
        p.before = p.after = null;
		//b==null 标识p(e)的上一个节点为null,也就是p为 头部节点的before为null);
		//需要将p下一个节点设置为头结点
        if (b == null)
            head = a;
		//b!=null 标识p(e)的上一个节点存在值,也就是p不为头部节点的before为null);
		//需要将p的上一个节点指向p的下一个节点(此处注意p的下一个节点并没有指向p的上一个节点)
        else
            b.after = a;
		
		//a == null a(p的下一个节点)为空,也就是p是尾部;
		//tail 的引用指向b(p的上一个节点)的
        if (a == null)
            tail = b;
		//a != null p的下一个节点不是空,也就是p不是尾部;
		//那么将a(p下一个节点)的上一个节点指向 b(p的上一个节点)
        else
            a.before = b;
    }

	/**
	 * 是用与插入新元素是否需要删除头部元素,一般不会删除,
	 * 只有重写其内部的方法removeEldestEntry(Map.Entry<K,V> eldest)才会实现删除,并且参数evict=true
	*/
    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);
        }
    }
	/**
	 * put使用存在的key和get使用
	 * 将新更新的节点放在双向链表最后
	 * 全局变量 head(存储链表头部),tail (存储链表尾部)
	*/
    void afterNodeAccess(Node<K,V> e) { 
		//临时存储尾部
        LinkedHashMap.Entry<K,V> last;
		//LinkedHashMap设置了操作排序,并且e不是尾部节点
        if (accessOrder && (last = tail) != e) {
			//用p存储当前节点e, b存储p(e)的上一个节点,a存储p(e)的下一个节点
            LinkedHashMap.Entry<K,V> p =
                (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
			//令p的下一个节点指向null(尾部节点的after一定的是null,头部节点的before为null)
            p.after = null;
			//b==null 标识p(e)的上一个节点为null,也就是p为 头部节点的before为null);
			//需要将p下一个节点设置为头结点
            if (b == null)
                head = a;
			//b!=null 标识p(e)的上一个节点存在值,也就是p不为头部节点的before为null);
			//需要将p的上一个节点指向p的下一个节点(此处注意p的下一个节点并没有指向p的上一个节点)
            else
                b.after = a;
			
			//a != null p的下一个节点不是空,也就是p不是尾部;
			//那么将a(p下一个节点)的上一个节点指向 b(p的上一个节点)
            if (a != null)
                a.before = b;
			//a == null a(p的下一个节点)为空,也就是p是尾部;
			//last 的引用指向b(p的上一个节点)的
            else
                last = b;
			
			//如果 last == null ,头部为p
            if (last == null)
                head = p;
			//如果 last != null ,p的上一个节点指向last,last的下一个节点指向p
            else {
                p.before = last;
                last.after = p;
            }
			//尾部指向新加的节点p
            tail = p;
            ++modCount;
        }
    }

    void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
            s.writeObject(e.key);
            s.writeObject(e.value);
        }
    }

    /**
     * 与HashMap初始化类似
     */
    public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }

    /**
     *与HashMap初始化类似
     */
    public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }

    /**
     *与HashMap初始化类似
     */
    public LinkedHashMap() {
        super();
        accessOrder = false;
    }

    /**
     *与HashMap初始化类似
     */
    public LinkedHashMap(Map<? extends K, ? extends V> m) {
        super();
        accessOrder = false;
		//HashMap中的方法
        putMapEntries(m, false);
    }

    /**
     *与HashMap初始化类似
     * @param  initialCapacity map容量
     * @param  loadFactor 负载系数
     * @param  accessOrder  内部排序方式: 访问顺序排序(ture) ; 存储顺序排序(false)
     */
    public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }


    /**
     * Returns <tt>true</tt> if this map maps one or more keys to the
     * specified value.
     *
     * @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) {
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
            V v = e.value;
            if (v == value || (value != null && value.equals(v)))
                return true;
        }
        return false;
    }

    /**
     * 重写了HashMap get方法
     */
    public V get(Object key) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) == null)
            return null;
        if (accessOrder)
            afterNodeAccess(e);
        return e.value;
    }

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

    /**
     * 清空,与HashMap相比 多了个维护链表头、尾部
     */
    public void clear() {
        super.clear();
        head = tail = null;
    }

   
    public Set<K> keySet() {
        Set<K> ks = keySet;
        if (ks == null) {
            ks = new LinkedKeySet();
            keySet = ks;
        }
        return ks;
    }

    final class LinkedKeySet extends AbstractSet<K> {
        public final int size()                 { return size; }
        public final void clear()               { LinkedHashMap.this.clear(); }
        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);
        }
        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);
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }

   
    public Collection<V> values() {
        Collection<V> vs = values;
        if (vs == null) {
            vs = new LinkedValues();
            values = vs;
        }
        return vs;
    }

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

   
    public Set<Map.Entry<K,V>> entrySet() {
        Set<Map.Entry<K,V>> es;
        return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
    }

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

    // Map overrides

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

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

    // Iterators

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

    final class LinkedKeyIterator extends LinkedHashIterator
        implements Iterator<K> {
        public final K next() { return nextNode().getKey(); }
    }

    final class LinkedValueIterator extends LinkedHashIterator
        implements Iterator<V> {
        public final V next() { return nextNode().value; }
    }

    final class LinkedEntryIterator extends LinkedHashIterator
        implements Iterator<Map.Entry<K,V>> {
        public final Map.Entry<K,V> next() { return nextNode(); }
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值