1.5get方法
get方法也是多了:判断是否为访问顺序~~~
讲到了这里,感觉我们可以简单测试一波了:
首先我们来看看已插入顺序来进行插入和遍历:
public static void insertOrder() { // 默认是插入顺序 LinkedHashMap<Integer,String> insertOrder = new LinkedHashMap(); String value = "关注公众号Java3y"; int i = 0; insertOrder.put(i++, value); insertOrder.put(i++, value); insertOrder.put(i++, value); insertOrder.put(i++, value); insertOrder.put(i++, value); //遍历 Set<Integer> set = insertOrder.keySet(); for (Integer s : set) { String mapValue = insertOrder.get(s); System.out.println(s + "---" + mapValue); } }
测试一波:
接着,我们来测试一下以访问顺序来进行插入和遍历:
public static void accessOrder() { // 设置为访问顺序的方式 LinkedHashMap<Integer,String> accessOrder = new LinkedHashMap(16, 0.75f, true); String value = "关注公众号Java3y"; int i = 0; accessOrder.put(i++, value); accessOrder.put(i++, value); accessOrder.put(i++, value); accessOrder.put(i++, value); accessOrder.put(i++, value); // 遍历 Set<Integer> sets = accessOrder.keySet(); for (Integer key : sets) { String mapValue = accessOrder.get(key); System.out.println(key + "---" + mapValue); } }
代码看似是没有问题,但是运行会出错的!
前面在看源码注释的时候我们就发现了:在AccessOrder的情况下,使用get方法也是结构性的修改!
为了简单看出他俩的区别,下面我就直接用key来进行看了~
以下是访问顺序的测试:
public static void accessOrder() { // 设置为访问顺序的方式 LinkedHashMap<Integer,String> accessOrder = new LinkedHashMap(16, 0.75f, true); String value = "关注公众号Java3y"; int i = 0; accessOrder.put(i++, value); accessOrder.put(i++, value); accessOrder.put(i++, value); accessOrder.put(i++, value); accessOrder.put(i++, value); // 访问一下key为3的元素再进行遍历 accessOrder.get(3); // 遍历 Set<Integer> sets = accessOrder.keySet(); for (Integer key : sets) { System.out.println(key ); } }
测试结果:
以下是插入顺序的测试(代码就不贴了,和上面几乎一样):
我们可以这样理解:最常用的将其放在链表的最后,不常用的放在链表的最前~
这个知识点以我的理解而言,它这个访问顺序在LinkedHashMap如果不重写用处并不大~它是用来给别的实现进行扩展的
- 因为最常被使用的元素再遍历的时候却放在了最后边,在LinkedHashMap中我也没找到对应的方法来进行调用~
- 一个
removeEldestEntry(Map.Entry<K,V> eldest)方法,重写它可以删除最久未被使用的元素!! - 还有一个是
afterNodeInsertion(boolean evict)方法,新增时判断是否需要删除最久未被使用的元素!!
去网上搜了几篇资料,都是讲LRUMap的实现的(也就是对LinkedHashMap进行扩展),有兴趣的同学可参考下列链接:
- https://blog.csdn.net/exceptional_derek/article/details/11713255
- http://www.php.cn/java-article-362041.html
- https://www.jianshu.com/p/1a66529e1a2e
- https://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ%3D%3D&chksm=ebd639d5dca1b0c3ba5a26bd46d265544f4fdd468df6465e54d93da230c3457d4947e79eaf0c&idx=1&mid=2247485177&sn=93cfa2c2e6f3e5092e5850bdb5ea4cc3
1.6remove方法
对于remove方法,在LinkedHashMap中也没有重写,它调用的还是父类的HashMap的remove()方法,在LinkedHashMap中重写的是:afterNodeRemoval(Node<K,V> e)这个方法
当然了,在remove的时候会涉及到上面重写的方法:
1.7遍历的方法
Set<Map.Entry<K,V>> entrySet()是被重写的了
看到了这里,我们就知道为啥注释说:初始容量对遍历没有影响
因为它遍历的是LinkedHashMap内部维护的一个双向链表,而不是散列表(当然了,链表双向链表的元素都来源于散列表)
二、总结
LinkedHashMap比HashMap多了一个双向链表的维护,在数据结构而言它要复杂一些,阅读源码起来比较轻松一些,因为大多都由HashMap实现了..
阅读源码的时候我们会发现多态是无处不在的~子类用父类的方法,子类重写了父类的部分方法即可达到不一样的效果!
- 比如:LinkedHashMap并没有重写put方法,而put方法内部的
newNode()方法重写了。LinkedHashMap调用父类的put方法,里面回调的是重写后的newNode(),从而达到目的!
LinkedHashMap可以设置两种遍历顺序:
- 访问顺序(access-ordered)
- 插入顺序(insertion-ordered)
- 默认是插入顺序的
对于访问顺序,它是LRU(最近最少使用)算法的实现,要使用它要么重写LinkedListMap的几个方法(removeEldestEntry(Map.Entry<K,V> eldest)和afterNodeInsertion(boolean evict)),要么是扩展成LRUMap来使用,不然设置为访问顺序(access-ordered)的用处不大~
LinkedHashMap遍历的是内部维护的双向链表,所以说初始容量对LinkedHashMap遍历是不受影响的











