zoukankan      html  css  js  c++  java
  • Java集合之LinkedHashMap常用方法解析

       最近正准备回顾一下Java,所以在此做一些记录。

    LinkedHashMap继承了HashMap,大多数的操作调用的是HashMap的实现,在进行操作的时候多维护了一层双向链表

    LinkedHashMap的节点也继承了HashMap的节点,多维护了前置节点和后置节点两个属性

    1  static class Entry<K,V> extends HashMap.Node<K,V> {
    2         Entry<K,V> before, after;
    3         Entry(int hash, K key, V value, Node<K,V> next) {
    4             super(hash, key, value, next);
    5         }
    6     }
    View Code

    1.put(K key, V value) 存放一个键值对,其实是调用了HashMap的put方法,通过重写HashMap里的部分方法来实现链表的维护

     1 HashMap的put方法会生成一个节点,调用了newNode方法,而LinkedHashMap重写了此方法
     2  /**
     3      * 创建一个节点
     4      * @param hash  hash值
     5      * @param key   键
     6      * @param value 值
     7      * @param e     下一个节点,这个是HashMap节点的属性
     8      * @return
     9      */
    10     Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
    11         //调用构造方法
    12         LinkedHashMap.Entry<K,V> p =
    13             new LinkedHashMap.Entry<K,V>(hash, key, value, e);
    14         //维护链表
    15         linkNodeLast(p);
    16         return p;
    17     }
    18 
    19 /**
    20      * 添加一个节点到末尾
    21      * @param p 节点
    22      */
    23     private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
    24         //保存尾部节点
    25         LinkedHashMap.Entry<K,V> last = tail;
    26         //更新尾部节点
    27         tail = p;
    28         //判断之前的尾部节点是否为空
    29         if (last == null)
    30             //之前的尾部节点为空,说明还没有数据,设置一下头节点
    31             head = p;
    32         else {
    33             //说明之前已经有数据了,将新的节点作为尾部节点连接起来
    34             p.before = last;
    35             last.after = p;
    36         }
    37     }
    38 
    39 HashMap当put一个已经存在的key时,会触发是否更新的操作,之后会调用afterNodeAccess方法,LinkedHashMap重写了此方法
    40 /**
    41      * accessOrder为true时,将操作的节点移到链表尾部
    42      * @param e 节点
    43      */
    44     void afterNodeAccess(Node<K,V> e) {
    45         LinkedHashMap.Entry<K,V> last;
    46         //accessOrder 这个参数是指在进行操作的时候,是否将操作的节点移动到链表的最后,默认false
    47         //也就是说accessOrder为false的时候链表就是按照插入顺序维护的
    48         //true的时候,会将最近使用的节点移动到链表最后
    49         if (accessOrder && (last = tail) != e) {
    50             //保存当前节点和其前置节点和后置节点
    51             LinkedHashMap.Entry<K,V> p =
    52                 (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
    53             //清空后置节点,因为当前节点要被移动到最后了
    54             p.after = null;
    55             //判断前置节点是否为空节点
    56             if (b == null)
    57                 //前置节点为空,说明当前节点是头节点,将它的后置节点也就是第二个节点设置为头节点
    58                 head = a;
    59             else
    60                 //存在前置节点,将前置节点的后置节点连接到当前节点的下一个节点
    61                 b.after = a;
    62             //判断后置节点是否为空
    63             if (a != null)
    64                 //后置节点不为空,更新后置节点的前置节点
    65                 a.before = b;
    66             else
    67                 //说明该节点就是尾部节点,设置前置节点为后节点
    68                 //a == null 说明p就是尾部节点? 有点不清楚
    69                 last = b;
    70             //统一更新尾部节点
    71             if (last == null)
    72                 //说明只有这么一个节点
    73                 head = p;
    74             else {
    75                 //将当前节点挂到链表末尾
    76                 p.before = last;
    77                 last.after = p;
    78             }
    79             //设置尾部节点
    80             tail = p;
    81             ++modCount;
    82         }
    83     }
    84 
    85 LinkedHashMap也重写了afterNodeInsertion方法
    86 void afterNodeInsertion(boolean evict) {
    87         LinkedHashMap.Entry<K,V> first;
    88         if (evict && (first = head) != null && removeEldestEntry(first)) {
    89             K key = first.key;
    90             removeNode(hash(key), key, null, false, true);
    91         }
    92     }
    93 
    94 protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
    95         return false;
    96     }
    97 
    98 其实LinkedHashMap中这个方法并不生效
    View Code

    2.get(Object key) 根据key获取值

     1 /**
     2      * 获取值
     3      * @param key 键
     4      * @return
     5      */
     6     public V get(Object key) {
     7         Node<K,V> e;
     8         //调用了HashMap中的getNode方法
     9         if ((e = getNode(hash(key), key)) == null)
    10             return null;
    11         if (accessOrder)
    12             //移动当前操作的节点到链表最后
    13             afterNodeAccess(e);
    14         return e.value;
    15     }
    View Code

    3. containsValue(Object value) 是否存在某个值

    1  public boolean containsValue(Object value) {
    2         //通过遍历链表实现
    3         for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
    4             V v = e.value;
    5             if (v == value || (value != null && value.equals(v)))
    6                 return true;
    7         }
    8         return false;
    9     }
    View Code

    4.remove(Object key)  删除key

     1 LinkedHashMap调用了HashMap的remove方法
     2 重写了afterNodeRemoval方法
     3  /**
     4      * 删除链表中的节点
     5      * @param e
     6      */
     7     void afterNodeRemoval(Node<K,V> e) {
     8         //获取当前节点的前置后置节点
     9         LinkedHashMap.Entry<K,V> p =
    10             (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
    11         //清空前置后置节点
    12         p.before = p.after = null;
    13         
    14         if (b == null)
    15             //前置节点为空,说明为头节点,更新头节点为后置节点
    16             head = a;
    17         else
    18             //前置节点不为空,设置前置节点的后置节点为删除节点的后置节点
    19             b.after = a;
    20         if (a == null)
    21             //后置节点为空,说明为尾部节点,更新尾部节点为其前置节点
    22             tail = b;
    23         else
    24             //后置节点不为空,更新后置节点的前置节点
    25             a.before = b;
    26     }
    View Code
  • 相关阅读:
    wince 操作sqlite数据库
    c#数据结构(第二章)
    C#数据结构(第三章)
    近期学习(收藏地址)
    c#数据结构(第四章)
    PowerDesigner 数据库设计
    wince操作远程sqlserver数据库
    一个有趣的算法
    c#数据结构(第一章)
    c#实现显示图片的动态效果
  • 原文地址:https://www.cnblogs.com/hdllhd/p/11776399.html
Copyright © 2011-2022 走看看