对LinkedHashMap的理解

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/anjing900812/article/details/52250946
  • 最初的认识:
    • 可以维护元素的插入顺序,按照插入顺序遍历;
    • 实现原理:LinkedHashmap的Entry除了该节点的hash值、key值、value值、next指向冲突时的后一个节点,还增加了指向前一个节点和后一个节点的指针:before、after,从而构成双向链表;除此之外,还有双向链表的头结点head和尾节点tail;
  • LinkedHashMap的具体实现:
    • 节点:
      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);
           }
       }
    • 头指针和尾指针:使用了transient关键字,该字段不进行序列化
      transient LinkedHashMap.Entry<K,V> head;
      transient LinkedHashMap.Entry<K,V> tail;
    • 元素的两种顺序:插入顺序、访问顺序(accessorder,可以用于实现LRU cache);
    • 插入顺序:遍历LinkedHashMap时,按照元素插入的顺序输出,put时,新元素追加在链表的尾部即可;
    • 访问顺序:创建LinkedHashMap时,传入参数accessorder指定为true,即表示按照访问顺序遍历数组;此刻,头部是最久未被访问的节点,尾部是最近刚访问过的节点;
      • get,如果该元素存在,则将节点从原位置删除,插入尾部;
      • put:如果新插入的元素key已存在,则替换其value,并将它从原位置删除,再插入尾部,如果不存在,则直接插入尾部;
    • 方法:removeEldestEntry
    • protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
              return false;
      }
      重写该方法,可以指定在put元素时删除最久未被访问的,即双向链表头部的节点,从而实现LRU cache,默认不会删除。
  • LinkedHashmap的遍历
    • 使用EntrySet和迭代器;该例子中使用访问顺序,所以get操作会改变节点的顺序;
    • public static void main(String[] args)  {
      	LinkedHashMap<String,Integer> map = new LinkedHashMap<String,Integer>(16,(float) 0.75,true);
      	map.put("er", 1);
      	map.put("rt", 2);
      	map.put("ui", 3);
      	map.put("op", 4);
      	map.get("er");
      	map.get("ui");
      	Set<Entry<String, Integer>>  set = map.entrySet();
      	Iterator<Entry<String, Integer>> itr = set.iterator();
      	while(itr.hasNext()){
      		Entry<String,Integer> ele = itr.next();
      		System.out.println(ele.getKey()+" "+ele.getValue());
      	}
      }
    • 如果使用下面这种方式遍历,就会抛异常;
    • public static void main(String[] args)  {
      	LinkedHashMap<String,Integer> map = new LinkedHashMap<String,Integer>(16,(float) 0.75,true);
      	map.put("er", 1);
      	map.put("rt", 2);
      	map.put("ui", 3);
      	map.put("op", 4);
      	Set<String> keyset = map.keySet();
      	Iterator itr = keyset.iterator();
      	while(itr.hasNext()){
      		System.out.println(map.get(itr.next()));
      	}
      }
      1
      Exception in thread "main" java.util.ConcurrentModificationException
      	at java.util.LinkedHashMap$LinkedHashIterator.nextNode(Unknown Source)
      	at java.util.LinkedHashMap$LinkedKeyIterator.next(Unknown Source)
      	at 验证例子.LinkedListTest.main(LinkedListTest.java:28)
      这是因为,new LinkedHashMap时,若指定accessorder为true,则get方法会调用afterNodeAccess方法,改变元素的位置,将其插入尾部,同时modCount++,所以调用Iterator 的next时,发现expectedModCount和modCount不一样,抛出ConcurrentModificationException;这是同步容器类的fail-fast机制;
  • 使用LinkedHashMap实现LRU cache


展开阅读全文

没有更多推荐了,返回首页