zoukankan      html  css  js  c++  java
  • LinkedHashMap为什么是有序的(与put先后顺序一致)

     本文版权归 远方的风lyh和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作,如有错误之处忘不吝批评指正!

    絮叨絮叨

      首先呢,明白一点 LinkedHashMap是HashMap的子类,也就是说它就是一个HashMap(所以还是要对HashMap源码有一定了解),至于它可以保证(有序)先后顺序,只能说儿子比老子优秀!虎父无犬子,儿子在父亲的基业上又有了独到之处!原因呢?下面一起看看源码((基于jdk1.8)就知晓了!(看源码一定要有耐心,第一次看可能看不懂,后面再看可能还是看不懂,但是别放弃治疗)。

        

    public class LinkedHashMap<K,V>
        extends HashMap<K,V>
        implements Map<K,V>
    {
    }

    源码分析

     变量分析

       LinkedHashMap在HashMap基础上扩展的这两个成员变量要特别注意,这两个变量是保证有序的基础

        /**
         * The head (eldest) of the doubly linked list.
    * 记录第一个 key—value 对象关于
    LinkedHashMap.Entry<K,V>的结构接下来就会分析
    */
       transient LinkedHashMap.Entry<K,V> head; /** * The tail (youngest) of the doubly linked list.
    * 保存最后一个 key—value 对象
    */ transient LinkedHashMap.Entry<K,V> tail;

       

     LinkedHashMap.Entry<K,V>结构:

      它继承了HashMap.Node<K,V>,  添加了两个LinkedHashMap.Entry<K,V> 用来记录它的前一个 和后一个put进入来的key-value对象(LinkedHashMap.Entry<K,V>),在在结构设计上保证了LinkedHashMap有序的可实现

       static class Entry<K,V> extends HashMap.Node<K,V> {
    //它的前一个 和后一个put进入来的key-value对象 Entry
    <K,V> before, after; Entry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); } }

       附上HashMap.Node<K,V>

    static class Node<K,V> implements Map.Entry<K,V> {
            final int hash;
            final K key;
            V value;
            Node<K,V> next;
    
            Node(int hash, K key, V value, Node<K,V> next) {
                this.hash = hash;
                this.key = key;
                this.value = value;
                this.next = next;
            }
            //省略。。。。。。。
        }

     实现

         了解完结构我们再来看看它在代码中是如何实现的,LinkedHashMap是HashMap的子类 ,在放入key-value时,它复用了HashMap的put方法

    public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
        }
    

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) //这里要格外注意 LinkedHashMap复写了HashMap的 //newNode(hash, key, value, null) 方法 tab[i] = newNode(hash, key, value, null); //...... }
      LinkedHashMap复写了HashMap的newNode(hash, key, value, null) 方法,代码如下:
     1  Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
     2         LinkedHashMap.Entry<K,V> p =
     3             new LinkedHashMap.Entry<K,V>(hash, key, value, e);
     4         linkNodeLast(p);
     5         return p;
     6     }
     7 /***有序的实现核心***/
     8 private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
     9     LinkedHashMap.Entry<K,V> last = tail;
    10     tail = p;
    11     if (last == null)
    12         head = p;
    13     else {
    14         p.before = last;
    15         last.after = p;
    16     }
    17 }

       举一个场景来说明上面的有序核心实现方法,比如说有这么一个场景:  一个班有 1号小明同学 2号张三 3号小红 4号李四同学,老师要知道学生进入教师的先后顺序。老师在黑板上写了 两个词  head,tail两个字段 规定:

        1.第一个来的在 head来的在head、tail写上自己的名字

        2.第二个及后续到的, 看到黑板上的tail字段后,找到这个同学(这个同学记住我之后到的 after) 通知自己到了(并记住在我之前的是这个同学before) 并修改tail字段为自己的名字

      例子:

        1.小明同学 第一个到  ,在黑板上 head,tail 都写下 小明

        2.张三到了之后看到 tail是小明 记住 自己上一个(before)是小明 ,并修改tail为张三 ,通知小明,小明记下来自己的后面(afte)r是张三

        3小红到了看到tail是张三 记住自己上一个(before)是张三 并修改tail为小红,通知张三,张三记下来自己的后面(after)是小红

        4李四到了。。。。。。。

      老师来了上课 看到head上写的是小明  并询问 小明 你后面是谁 , 小明回:小红 再询问 小红 ....知道 询问到李四 结束

      老师就知道了学生进入教室的顺序 小明->张三->小红->李四。

  • 相关阅读:
    Java Web学习总结(9)——servlet和Jsp生命周期解读
    Java Web学习总结(9)——servlet和Jsp生命周期解读
    Java Web学习总结(10)——Session详解
    Java Web学习总结(10)——Session详解
    Mysql学习总结(6)——MySql之ALTER命令用法详细解读
    Mysql学习总结(6)——MySql之ALTER命令用法详细解读
    十大热门问题集锦,一眼看懂华为云数据库黑科技
    python上下文管理器细读
    关于token你需要知道的
    使用app测试Modelarts在线服务
  • 原文地址:https://www.cnblogs.com/lyhc/p/10743550.html
Copyright © 2011-2022 走看看