LinkedHashMap 可以看作是 HashMap 和 LinkedList 的结合:它在 HashMap 的基础上添加了一条双向链表,默认存储各个元素的插入顺序,但由于这条双向链表,使得 LinkedHashMap 可以实现 LRU缓存淘汰策略,因为我们可以设置这条双向链表按照元素的访问次序进行排序,它是非线程安全的。
整体架构
LinkedHashMap 本身是继承 HashMap 的,所以它拥有 HashMap 的所有特性,其次,它在 HashMap 的基础上维护了一条双向链表,该链表存储了所有元素,默认元素的顺序与插入顺序一致。若accessOrder属性为true,则遍历顺序按元素的访问次序进行排序。
LinkedHashMap提供了两大特性:
1:按照插入顺序进行访问;
2:实现了访问最少最先删除功能,其目的是把很久都没有访问的 key 自动删除。
LinkedHashMap主要操作
// 初始化方法1
LinkedHashMap<Object, Object> map = new LinkedHashMap<>();
// 初始化方法2
LinkedHashMap<Object, Object> map1 = new LinkedHashMap<>(16, 0.75f);
//初始化方法3
LinkedHashMap<Object, Object> map2 = new LinkedHashMap<>(map);
//初始化方法4
LinkedHashMap<Object, Object> map3 = new LinkedHashMap<>(16);
map3.put("One", "1");
map3.put("Two", "2");
map3.put("Three", "3");
map3.put("Five", "5");
map3.put("Four", "4");
map3.put("Six", "6");
map3.put("Seven", "7");
for (Object str : map3.keySet()) {
System.out.println(map3.get(str));
}
插入顺序访问
1:LinkedHashMap 链表结构,新增的相关属性
// 链表头
transient LinkedHashMap.Entry<K,V> head;
// 链表尾
transient LinkedHashMap.Entry<K,V> tail;
// 继承 Node,为数组的每个元素增加了 before 和 after 属性
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);
}
}
// 控制两种访问模式的字段,默认 false
// true 按照访问顺序,会把经常访问的 key 放到队尾
// false 按照插入顺序提供访问
final boolean accessOrder;
因为增加了上述结构,从而能把 Map 的元素都串联起来,形成一个链表,而链表就可以保证顺序了,就可以维护元素插入进来的顺序。
2:如何按照顺序新增
LinkedHashMap 初始化时,默认 accessOrder 为 false,就是会按照插入顺序提供访问,插入方法使用的是父类 HashMap 的 put 方法,每次新增时,都把节点追加到尾节点等手段,在新增的时候,就已经维护了按照插入顺序的链表结构了。
3:按照顺序访问
LinkedHashMap 只提供了单向访问,即按照插入的顺序从头到尾进行访问,不能像 LinkedList 那样可以双向访问。主要通过迭代器进行访问,迭代器初始化的时候,默认从头节点开始访问,在迭代的过程中,不断访问当前节点的 after 节点即可。Map 对 key、value 和 entrty(节点) 都提供出了迭代的方法,假设需要迭代 entrty,就可使用 LinkedHashMap.entrySet().iterator() 这种写法直接返回 LinkedHashIterator ,LinkedHashIterator 是迭代器,调用迭代器的 nextNode 方法就可以得到下一个节点。
访问最少删除策略
这种策略也叫做 LRU(Least recently used,最近最少使用),大概的意思就是经常访问的元素会被追加到队尾,这样不经常访问的数据自然就靠近队头,然后可以通过设置删除策略,比如当 Map 元素个数大于多少时,把头节点删除。