LinkedHashMap是一个根据某种规则有序的hashmap。根据名字,咱们也能够看出这个集合是有hash散列的功能的同时也有顺序。hashmap是没法根据某种顺序来访问数据的,例如放入集合的元素前后的顺序。list都有这个功能,能够根据放入集合的前后来访问具体的数据。这里你们也确定是有疑问的,例如都已经使用了hash了,为何还要去保证顺序访问。这个在后面的场景中解释。java
当刚遇到这个集合的时候,我也疑惑,能同时知足条件的数据结构到底是怎么样的。若是没有思考这个问题,还请看到这里好好想一想。 ---------滑稽分割-------- 答案确实是没有这样的数据结构。他是两种结构的组合。一种是咱们熟悉的hashmap。另一种就是链表。数据存入集合的时候,先根据hashmap的流程存放入数组中。而后再根据链表的原则,进行连接。 若是看源码,也会发现其实没有多少方法。基本都是继承自hashmap的。数组
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
咱们来看看串联逻辑的几个操做
节点组成缓存
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); } }
能够看出。相比hashmap的节点。linkedhashmap主要增长before, after。能够组成一个双向链表。
节点加入数据结构
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) { LinkedHashMap.Entry<K,V> last = tail;//获取最后一个节点 tail = p;//tail指向新加入的节点 if (last == null)//链表为空 head = p; else { p.before = last; last.after = p; } } //新建节点的时候把节点加入了双向链表 Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) { LinkedHashMap.Entry<K,V> p = new LinkedHashMap.Entry<K,V>(hash, key, value, e); linkNodeLast(p); return p; }
删除状况也是相似。
节点访问code
public V get(Object key) { Node<K,V> e; if ((e = getNode(hash(key), key)) == null) return null; if (accessOrder)//是否根据某种顺序 afterNodeAccess(e);//把访问节点加入到尾节点 return e.value; }
afterNodeAccess中主要是把访问的节点从原来的位置摘除,加入到尾节点,成为链表的最后一个元素。继承
顺序遍历和快速定位
LinkedHashMap适合有加入顺序和快速定位的场景。我本身开发中遇到过一个场景,就是把配置顺序读取,须要按照读取的顺序访问,并且还须要根据值key直接获取值。这个场景就须要使用LinkedHashMap。
缓存
LinkedHashMap另一个强大的功能就是作缓存。不过咱们要继承一下。去重写一个方法。队列
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {//默认是没有操做 return false; }
这个方法在插入以后会被调用到。开发
void afterNodeInsertion(boolean evict) { // possibly remove eldest LinkedHashMap.Entry<K,V> first; if (evict && (first = head) != null && removeEldestEntry(first)) {//删除第一个元素 K key = first.key; removeNode(hash(key), key, null, false, true); } }
LinkedHashMap支持两种缓存策略。FIFO和LRU。你们应该也猜到控制策略的地方就是accessOrder。默认为false。就是FIFO。设置为true时就是LRU。由于在访问的时候会调整链表结构,调用afterNodeAccess会把访问的节点放入队列最后。因此每次删除first就能够达到效果。我通常会选择继承LinkedHashMap。而后重写removeEldestEntry,例如能够元素个数达到200范围true。这里须要根据具体场景来编写。rem