HashMap大家都很了解,是一中比较常用的,也比较好用的集合,但是HashMap有一个顺序的问题,就是在对HashMap进行迭代访问时,添加的顺序和访问的顺序可能就不一样的,这个时候我们可以选择LinkedHashMap,
LinkedHashMap继承了HashMap,所以拥有和HashMap一样的功能;而且在此基础上有增加了一个双向链表来实现元素迭代的顺序,但是肯定会增加时间和空间的消耗,
LinkedHashMap和HashMap一样,也是非线程安全的

我们还是先来看一个LinkedHashMap的实例,操作数据的方法和HasMap是一样的,代码如下:

java LinkedBlockingDeque 入门 java linkedmap_java

java LinkedBlockingDeque 入门 java linkedmap_链表_02

1 public static void main(String[] args) {
 2     LinkedHashMap<String, Object> hasMap = new LinkedHashMap<String, Object>();
 3     hasMap.put("name", "zhangsan");
 4     hasMap.put("age", 20);
 5     hasMap.put("addr", "北京市");
 6     hasMap.put(null, null);
 7     hasMap.put("info", null);
 8     hasMap.put(null, "who");
 9 
10     for (Map.Entry<String, Object> entry : hasMap.entrySet()) {
11         System.out.println(entry.getKey() + "=" + entry.getValue());
12     }
13 }

View Code

输出结果:
name=zhangsan
age=20
addr=北京市
null=who
info=null

根据输出我们可以得出以下几个结论:
LinkedHashMap的输入顺序和输出顺序是一致的。
LinkedHashMap允许Key和Value都可以null
LinkedHashMap中添加元素时,如果Key重复,则后添加的会覆盖前面已经存在的值

 

LinkedHashMap的具体实现

我们先来看看LinkedHashMap的定义,其中157行有这样一个定义

1 /**
2 * The head of the doubly linked list.
3 */
4 private transient Entry<K,V> header;

java LinkedBlockingDeque 入门 java linkedmap_java_03

Entry就是LinkedHashMap基本数据结构,Entry是LinkedHashMap定义的一个内部类,继承了HaspMap.Entry,在此基础上添加了新添加了两个属性。
before、after是用于维护链表中Entry的前一个元素和后一个元素。

 我们来看一下HaspMap的一个构造函数,

1    public HashMap(int initialCapacity, float loadFactor) {
 2         if (initialCapacity < 0)
 3             throw new IllegalArgumentException("Illegal initial capacity: " +
 4                                                initialCapacity);
 5         if (initialCapacity > MAXIMUM_CAPACITY)
 6             initialCapacity = MAXIMUM_CAPACITY;
 7         if (loadFactor <= 0 || Float.isNaN(loadFactor))
 8             throw new IllegalArgumentException("Illegal load factor: " +
 9                                                loadFactor);
10 
11         this.loadFactor = loadFactor;
12         threshold = initialCapacity;
13         init();
14     }

此构造函数中最后有一个init的方法,但是此方法在HashMap中没有实现,LinkedHashMap中重写了该方法,用来初始化化链表。

java LinkedBlockingDeque 入门 java linkedmap_java_04

元素的添加,修改和HashMap就一样的,虽然LinkedHashMap重写了addEntry方法,只是增加了删除eldest entry的功能。

java LinkedBlockingDeque 入门 java linkedmap_linkhashmap_05

方法removeEldestEntry始终返回false, 所以删除 eldest entry 实际上不会执行。

总结:从以上可以判断LinkedHashMap的实现就是 HashMap+LinkedList 的实现方式,用HashMap维护数据结构,用LinkList的方式维护数据插入顺序。

 

 利用LinkedHashMap实现LRU算法缓存

转载自:

解释一下LRU:LRU即Least Recently Used,最近最少使用,也就是说,当缓存满了,会优先淘汰那些最近最不常访问的数据。
要实现这个功能,就是要记录那些元素被访问了,访问的元素应该向前排列,当然这个功能LinkedHashMap已经帮我们实现了,

 

java LinkedBlockingDeque 入门 java linkedmap_构造函数_06

注意红框的部分, recordAccess,就是将当前entry移动到链表的最前面。

 

前面说了,LinkedHashMap添加新的元素时会执行删除eldest entry,虽然LinkedHashMap没有实现,但是我们可以重写removeEldestEntry的方法来实现这个功能。 

1 public class LRUCache extends LinkedHashMap
 2 {
 3     public LRUCache(int maxSize)
 4     {
 5         super(maxSize, 0.75F, true);
 6         maxElements = maxSize;
 7     }
 8 
 9     protected boolean removeEldestEntry(java.util.Map.Entry eldest)
10     {
11         return size() > maxElements;
12     }
13 
14     private static final long serialVersionUID = 1L;
15     protected int maxElements;
16 }

当元素的个数大于指定的值有,就会有原始被删除掉,也就是链表最后的元素。