【JDK1.8集合】之LinkedHashMap

LinkedHashMap:是HashMap的子类,内部维护双向链表,元素有序,默认按照插入顺序排序,可以自定义按照访问顺序排序。

 

成员属性:

  //双向链表的头结点
    transient LinkedHashMap.Entry<K, V> head;

   //双向链表的尾结点
    transient LinkedHashMap.Entry<K, V> tail;

  // 是否按照访问顺序排序,
    // false--->存入顺序排序
    // true--->访问顺序排序
    final boolean accessOrder;

 

构造函数:

//无参构造
    //默认按照存入顺序排序
    public LinkedHashMap() {
        super();
        accessOrder = false;
    }

//指定容量构造
    public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }

  //指定容量和加载因子
    public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }

  //指定Map构造,
    public LinkedHashMap(Map<? extends K, ? extends V> m) {
        super();
        accessOrder = false;
        putMapEntries(m, false);
    }


 //自定义初始容量,加载因子,是否访问顺序
    //只有这个构造自定义了是否按照访问顺序排序,其他构造都是按照存入顺序排序
    public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

 

其他重要方法:

 此方法的逻辑就是,将当前节点,移动到双向链表的尾部,每次有元素被访问的时候,就会按照访问先后来排序,
//实现自HashMap
    void afterNodeAccess(Node<K, V> e) { // move node to last
        LinkedHashMap.Entry<K, V> last;
        //如果按照访问顺序排序,并且添加的元素不是双向链表的尾节点
        if (accessOrder && (last = tail) != e) {
            //记录当前节点为p,前后节点b,a;
            LinkedHashMap.Entry<K, V> p =
                    (LinkedHashMap.Entry<K, V>) e, b = p.before, a = p.after;
            //GC
            p.after = null;
            //如果当前节点没有前节点
            if (b == null)
                //将当前节点的后节点设置为头节点
                head = a;
                //如果有前节点
            else
                //将当前节点的后节点设置为当前节点的前节点的后节点
                b.after = a;

            //如果当前节点有后节点
            if (a != null)
                //将当前节点的前节点设置为当前节点的后节点的前节点
                a.before = b;
                //如果没有后节点
            else
                //将当前节点的前节点设置为最后一个节点
                last = b;
            //如果尾节点为null
            if (last == null)
                //将当前节点设置为首节点
                head = p;
            //尾节点不为null
            else {
                //将最后一个节点设置为当前节点的前节点
                p.before = last;
                //将当前节点设置为最后一个节点的后节点
                last.after = p;
            }
            //将当前节点p设置为尾节点
            tail = p;
            ++modCount;
            //此方法的逻辑就是,将当前节点,移动到双向链表的尾部,
            //每次有元素被访问的时候,就会按照访问先后来排序,
        }
    }

 

 

//实现自HashMap
    //将当前节点从双向链表中删除,
    void afterNodeRemoval(Node<K, V> e) { // unlink
        LinkedHashMap.Entry<K, V> p =
                (LinkedHashMap.Entry<K, V>) e, b = p.before, a = p.after;
        p.before = p.after = null;
        if (b == null)
            head = a;
        else
            b.after = a;
        if (a == null)
            tail = b;
        else
            a.before = b;
    }
    //实现自HashMap
    //当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);
        }
    }

 

元素获取:

  //如果元素按照插入顺序排序,直接返回
    //如果元素按照访问顺序排序,将当前key对应的节点移到链表末尾
    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;
    }

 

  //重写containsValue,利用双向链表的特点进行查询,提高查询效率
    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;
    }

 

LinkedHasMap 在SpringMVC (AbstractCachingViewResolver)中的应用:(重写removeEldestEntry()方法,)


 public static final int DEFAULT_CACHE_LIMIT = 1024;

    private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;

    private final Map<Object, View> viewAccessCache = new ConcurrentHashMap<Object, View>(DEFAULT_CACHE_LIMIT);


    private final Map<Object, View> viewCreationCache =
        //最大容量 DEFAULT_CACHE_LIMIT=1024,
             //true,按照访问顺序排序
            //
        new LinkedHashMap<Object, View>(DEFAULT_CACHE_LIMIT, 0.75f, true) {
        @Override
        protected boolean removeEldestEntry(Map.Entry<Object, View> eldest) {
            if (size() > getCacheLimit()) {
                viewAccessCache.remove(eldest.getKey());
                return true;
            }
            else {
                return false;
            }
        }
    };

 

LinkedHasMa的removeEldestEntry()方法:

//默认返回false,不删除最前面的元素,  
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return false;
    }

 

posted @ 2017-11-01 21:22  emoji的博客  阅读(417)  评论(0编辑  收藏  举报