LinkedHashMap如何保证顺序性(4)

大家看到区别了吗,accessOrder为false时,你访问的顺序就是按照你第一次插入的顺序;而accessOrder为true时,你任何一次的操作,包括put、get操作,都会改变map中已有的存储顺序。

3. afterNodeInsertion方法

我们看到在LinkedHashMap中还重写了afterNodeInsertion(boolean evict)方法,它的目的是移除链表中最老的节点对象,也就是当前在头部的节点对象,但实际上在JDK8中不会执行,因为removeEldestEntry方法始终返回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); } } protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return false; } 三. get方法

LinkedHashMap的get方法与HashMap中get方法的不同点也在于多了afterNodeAccess()方法

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; }

在这里就不再多讲了,getNode()方法在HashMap章节已经讲过,而前面刚把afterNodeAccess讲了。

四.remove方法

remove方法也直接使用了HashMap中的remove,在HashMap章节并没有讲解,因为remove的原理很简单,通过传递的参数key计算出hash,据此可找到对应的Node节点,接下来如果该Node节点是直接在数组中的Node,则将table数组该位置的元素设置为node.next;如果是链表中的,则遍历链表,直到找到对应的node节点,然后建立该节点的上一个节点的next设置为该节点的next。

LinkedHashMap重写了其中的afterNodeRemoval(Node e),该方法在HashMap中没有具体实现,通过此方法在删除节点的时候调整了双链表的结构。

void afterNodeRemoval(Node<K,V> e) { LinkedHashMap.Entry<K,V> p = (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after; //将待删除节点的before和after都设置为null p.before = p.after = null; /** * 如果节点b为null,表示待删除节点p为头部节点,该节点拿掉后,该节点的下一个节点a就为头部节点head * 否则设置待删除节点的上一个节点b的after属性为节点a */ if (b == null) head = a; else b.after = a; /** * 如果节点a为null,表示待删除节点p为尾部节点,该节点拿掉后,该节点的上一个节点a就为尾部节点tail * 否则设置待删除节点的下一个节点a的before属性为节点b */ if (a == null) tail = b; else a.before = b; } 五. 总结

LinkedHashMap使用的也较为频繁,它基于HashMap,用于HashMap的特点,又增加了双链表的结构,从而保证了顺序性,本文主要从源码的角度分析其如何保证顺序性,accessOrder的解释,以及常用方法的阐释,若有不对之处,请批评指正,望共同进步,谢谢!

linux

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/3eb4244de1c9d5f59a015a258f1dceca.html