• java的LinkedHashMap是如何保证顺序的


    介绍

    我们都知道HashMap添加完数据,取出来的顺序是混乱的,而LinkedHashMap可以保证查询的顺序和插入顺序保持一致。

    public class Client3 {
    
      public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("name", "lisi");
        map.put("gender", "male");
        map.put("address", "shanghai");
        map.put("mobile", "12345678908");
        for (Entry<String, String> entry : map.entrySet()) {
          System.out.println(entry);
        }
      }
    
    }
    

    输出结果为

    address=shanghai
    gender=male
    name=lisi
    mobile=12345678908
    

    可以看到HashMap确实不能保证顺序。

    public class Client4 {
    
      public static void main(String[] args) {
        Map<String, String> map = new LinkedHashMap<>();
        map.put("name", "lisi");
        map.put("gender", "male");
        map.put("address", "shanghai");
        map.put("mobile", "12345678908");
        for (Entry<String, String> entry : map.entrySet()) {
          System.out.println(entry);
        }
      }
    
    }
    

    输出结果为

    name=lisi
    gender=male
    address=shanghai
    mobile=12345678908
    

    LinkedHashMap保证了输出顺序和添加顺序一致,不仅如此,LinkedHashMap也可以根据访问顺序来输出。

    public class Client4 {
    
      public static void main(String[] args) {
       //true表示根据访问顺序,false表示插入顺序,默认false
        Map<String, String> map = new LinkedHashMap<>(16, 0.75f, true);
        map.put("name", "lisi");
        map.put("gender", "male");
        map.put("address", "shanghai");
        map.put("mobile", "12345678908");
        map.get("name");
        map.get("address");
        for (Entry<String, String> entry : map.entrySet()) {
          System.out.println(entry);
        }
      }
    
    }
    

    输出结果

    gender=male
    mobile=12345678908
    name=lisi
    address=shanghai
    

    可以看到一个key访问过就会被放到列表的最后。

    原理

    LinkedHashMap继承于HashMap,大部分功能直接使用HashMap的,少部分用自己的,LinkedHashMap通过自己另外保存一个链表来保证顺序

        /**
         * The head (eldest) of the doubly linked list.
         */
        transient LinkedHashMap.Entry<K,V> head;
    
        /**
         * The tail (youngest) of the doubly linked list.
         */
        transient LinkedHashMap.Entry<K,V> tail;
    
        Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
            LinkedHashMap.Entry<K,V> p =
                new LinkedHashMap.Entry<>(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<>(hash, key, value, next);
            linkNodeLast(p);
            return p;
        }
        // 将节点加到链表的最后
        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;
            }
        }
    

    LinkedHashMap重写了newNode方法和newTreeNode方法,在创建了节点后,将数据在链表中同样保存了一份。

        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;
        }
        // 将节点移动到最后
        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;
            }
        }
    

    通过重写get方法和afterNodeAccess方法实现了根据访问顺序排序。

  • 相关阅读:
    Python脚本运行出现语法错误:IndentationError: unindent does not match any outer indentation level
    Python3 运算符
    Python3 注释
    Python3 解释器
    Python3 环境搭建
    Python 3 教程
    Python3 基本数据类型
    趣闻|Python之禅(The Zen of Python)
    ios开发笔记根据传入字符串的长度动态生成label,并按照屏幕宽度排列
    iOS开发设置tableview的分割线
  • 原文地址:https://www.cnblogs.com/strongmore/p/14015638.html
Copyright © 2020-2023  润新知