zoukankan      html  css  js  c++  java
  • LinkedHashMap

    LinkedHashMap

    在java中,所有加了Link前缀的数据结构,都是可以按照顺序进行访问的,例如LinkedHashMap。LinkedHashMap和HashMap之间的区别在于它使用了一个双向链表将所有的entries链接起来。这个双向链表默认是按照entry的插入先后顺序构成的,如果重复插入一个key值相同的entry是不会影响链表的顺序的哦。

    LinkedHashMap也不是线程安全的,如果想要在多线程环境中使用,应该在构造的时候使用如下的语句:

    Map m = Collections.synchronizedMap(new LinkedHashMap(...));
    

    LinkedHashMap也是fail-fast的,如果在迭代过程中,LinkedHashMap的结构发生了变化,就会抛出ConcurrentModificationException异常。

    因为HashMap现在已经改为链表和红黑树两种存储方式了,LinkedHashMap作为HashMap的子类,也改变了自己的存储方式,所以LinkedHashMap不是按照链表来存储的。

    使用

    • 默认按照插入顺序排序
    import java.util.Iterator;
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    public class LinkedHashMapTest {
        public static void main(String[] args) {
            Map<String, Integer> test_map = new LinkedHashMap<String, Integer>();
    //        Map<String, Integer> test_map = new LinkedHashMap<String, Integer>(20, 0.7F, true);
            test_map.put("人类", 1);
            test_map.put("泰坦", 10);
            test_map.put("兽人", 2);
            test_map.put("精灵", 3);
    
            test_map.get("兽人");
            Iterator iter = test_map.entrySet().iterator();
    
            while (iter.hasNext()) {
                Map.Entry entry = (Map.Entry) iter.next();
                System.out.println(entry.getKey() + " : " + entry.getValue());
            }
        }
    }
    

    输出:

    人类 : 1
    泰坦 : 10
    兽人 : 2
    精灵 : 3
    

    上面的输出是按照输入的顺序来的,如果将LinkedHashMap变为HashMap就会发现输出的是一个无序的顺序了。

    • LinkedHashMap还有一种排序方式,类似于LRU,最近最久未使用,会将最不常用的entry排在最前。
    public class LinkedHashMapTest {
        public static void main(String[] args) {
    //        Map<String, Integer> test_map = new HashMap<String, Integer>();
            Map<String, Integer> test_map = new LinkedHashMap<String, Integer>(20, 0.7F, true);
            test_map.put("人类", 1);
            test_map.put("泰坦", 10);
            test_map.put("兽人", 2);
            test_map.put("精灵", 3);
    
            test_map.get("兽人");
            test_map.get("人类");
            Iterator iter = test_map.entrySet().iterator();
    
            while (iter.hasNext()) {
                Map.Entry entry = (Map.Entry) iter.next();
                System.out.println(entry.getKey() + " : " + entry.getValue());
            }
        }
    }
    

    输出:

    泰坦 : 10
    精灵 : 3
    兽人 : 2
    人类 : 1
    

    实现介绍

    实现方面,LinkedHashMap是在HashMap的基础上增加了对列表的操作。

    • Entry
        static class Entry<K,V> extends HashMap.Node<K,V> {
            Entry<K,V> before, after;
            Entry(int hash, K key, V value, Node<K,V> next) {
                super(hash, key, value, next);
            }
        }
    

    Entry的结构如上,每个Entry多了一个before 和 after 变量,分别指向链表前后的节点。

    • 构造函数

    LinkedHashMap的构造函数中有一个参数可以控制是否按照访问顺序进行排序,不过只有下面这个构造函数才可以使用,
    也就是必须同时传三个参数才可以。

        public LinkedHashMap(int initialCapacity,
                             float loadFactor,
                             boolean accessOrder) {
            super(initialCapacity, loadFactor);
            this.accessOrder = accessOrder;
        }
    
    • 将entry添加到链表中

    LinkedHashMap并不是在PUT函数中将entry添加到链表中,而是在新建entry(Node)的时候,添加到链表中。

        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;
        }
        
        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;
        }
    
    • 那么这个访问顺序修改是怎么实现的呢,它是在get函数中修改了链表的结构。
        public V get(Object key) {
            Node<K,V> e;
            if ((e = getNode(hash(key), key)) == null)
                return null;
            //如果accessOrder为真,就修改链表的顺序,将它放到链表的最后
            if (accessOrder)
                afterNodeAccess(e);
            return e.value;
        }
    	
    	void afterNodeAccess(Node<K,V> e) { // move node to last
            LinkedHashMap.Entry<K,V> last;
            //如果这个节点不是最后的节点,就将该节点放到最后
            if (accessOrder && (last = tail) != e) {
                LinkedHashMap.Entry<K,V> p =
                    (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
                p.after = null;
                if (b == null)
                    head = a;
                else
                    b.after = a;
                if (a != null)
                    a.before = b;
                else
                    last = b;
                if (last == null)
                    head = p;
                else {
                    p.before = last;
                    last.after = p;
                }
                tail = p;
                ++modCount;
            }
        }
    
  • 相关阅读:
    MDX Step by Step 读书笔记(六) Building Complex Sets (复杂集合的处理) Filtering Sets
    在 Visual Studio 2012 开发 SSIS,SSAS,SSRS BI 项目
    微软BI 之SSIS 系列 在 SSIS 中读取 SharePoint List
    MDX Step by Step 读书笔记(五) Working with Expressions (MDX 表达式) Infinite Recursion 和 SOLVE_ORDER 原理解析
    MDX Step by Step 读书笔记(五) Working with Expressions (MDX 表达式)
    使用 SQL Server 2012 Analysis Services Tabular Mode 表格建模 图文教程
    MDX Step by Step 读书笔记(四) Working with Sets (使用集合) Limiting Set and AutoExists
    SQL Server 2012 Analysis Services Tabular Model 读书笔记
    Microsoft SQL Server 2008 MDX Step by Step 学习笔记连载目录
    2011新的开始,介绍一下AgileEAS.NET平台在新的一年中的发展方向
  • 原文地址:https://www.cnblogs.com/SpeakSoftlyLove/p/5575207.html
Copyright © 2011-2022 走看看