【JDK1.8集合】之LinkedHashMap
LinkedHashMap:是HashMap的子类,内部维护双向链表,元素有序,默认按照插入顺序排序,可以自定义按照访问顺序排序。
成员属性:
//双向链表的头结点 transient LinkedHashMap.Entry<K, V> head; //双向链表的尾结点 transient LinkedHashMap.Entry<K, V> tail; // 是否按照访问顺序排序, // false--->存入顺序排序 // true--->访问顺序排序 final boolean accessOrder;
构造函数:
//无参构造 //默认按照存入顺序排序 public LinkedHashMap() { super(); accessOrder = false; } //指定容量构造 public LinkedHashMap(int initialCapacity) { super(initialCapacity); accessOrder = false; } //指定容量和加载因子 public LinkedHashMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); accessOrder = false; } //指定Map构造, public LinkedHashMap(Map<? extends K, ? extends V> m) { super(); accessOrder = false; putMapEntries(m, false); } //自定义初始容量,加载因子,是否访问顺序 //只有这个构造自定义了是否按照访问顺序排序,其他构造都是按照存入顺序排序 public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; }
其他重要方法:
此方法的逻辑就是,将当前节点,移动到双向链表的尾部,每次有元素被访问的时候,就会按照访问先后来排序,
//实现自HashMap void afterNodeAccess(Node<K, V> e) { // move node to last LinkedHashMap.Entry<K, V> last; //如果按照访问顺序排序,并且添加的元素不是双向链表的尾节点 if (accessOrder && (last = tail) != e) { //记录当前节点为p,前后节点b,a; LinkedHashMap.Entry<K, V> p = (LinkedHashMap.Entry<K, V>) e, b = p.before, a = p.after; //GC p.after = null; //如果当前节点没有前节点 if (b == null) //将当前节点的后节点设置为头节点 head = a; //如果有前节点 else //将当前节点的后节点设置为当前节点的前节点的后节点 b.after = a; //如果当前节点有后节点 if (a != null) //将当前节点的前节点设置为当前节点的后节点的前节点 a.before = b; //如果没有后节点 else //将当前节点的前节点设置为最后一个节点 last = b; //如果尾节点为null if (last == null) //将当前节点设置为首节点 head = p; //尾节点不为null else { //将最后一个节点设置为当前节点的前节点 p.before = last; //将当前节点设置为最后一个节点的后节点 last.after = p; } //将当前节点p设置为尾节点 tail = p; ++modCount; //此方法的逻辑就是,将当前节点,移动到双向链表的尾部, //每次有元素被访问的时候,就会按照访问先后来排序, } }
//实现自HashMap //将当前节点从双向链表中删除, void afterNodeRemoval(Node<K, V> e) { // unlink LinkedHashMap.Entry<K, V> p = (LinkedHashMap.Entry<K, V>) e, b = p.before, a = p.after; p.before = p.after = null; if (b == null) head = a; else b.after = a; if (a == null) tail = b; else a.before = b; } //实现自HashMap //当evict为true时,删除双向链表的头节点 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); } }
元素获取:
//如果元素按照插入顺序排序,直接返回 //如果元素按照访问顺序排序,将当前key对应的节点移到链表末尾 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; }
//重写containsValue,利用双向链表的特点进行查询,提高查询效率 public boolean containsValue(Object value) { for (LinkedHashMap.Entry<K, V> e = head; e != null; e = e.after) { V v = e.value; if (v == value || (value != null && value.equals(v))) return true; } return false; }
LinkedHasMap 在SpringMVC (AbstractCachingViewResolver)中的应用:(重写removeEldestEntry()方法,)
public static final int DEFAULT_CACHE_LIMIT = 1024; private volatile int cacheLimit = DEFAULT_CACHE_LIMIT; private final Map<Object, View> viewAccessCache = new ConcurrentHashMap<Object, View>(DEFAULT_CACHE_LIMIT); private final Map<Object, View> viewCreationCache = //最大容量 DEFAULT_CACHE_LIMIT=1024, //true,按照访问顺序排序 // new LinkedHashMap<Object, View>(DEFAULT_CACHE_LIMIT, 0.75f, true) { @Override protected boolean removeEldestEntry(Map.Entry<Object, View> eldest) { if (size() > getCacheLimit()) { viewAccessCache.remove(eldest.getKey()); return true; } else { return false; } } };
LinkedHasMa的removeEldestEntry()方法:
//默认返回false,不删除最前面的元素, protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return false; }
知识的学习,要真诚与谦虚才不会有眼无珠,人生苦短,不能浪费时间做无用功。
人生学习最悲哀的不过是,因为无知傲慢错过真正的好东西,又因为无知贪婪在假东西上耗费生命。