一、概述

LinkedHashMap继承自HashMap,是Map接口的一个具体实现,它是有序的,可以按照插入顺序先后和访问时间先后进行排序,选择哪种排序方式取决于在新建LinkedHashMap的时候是否指定了accessOrder为true。如果不指定,accessOrder默认为false,LinkedHashMap会按照插入顺序进行排序;入股指定为true,则会按照LRU算法将最少访问的元素排在前面。

LinkedHashMap中的removeEldestEntry(Map.Entry)方法默认返回false,如果重写,如:

private static final int MAX_ENTRIES = 100;

protected boolean removeEldestEntry(Map.Entry eldest) {

return size() > MAX_ENTRIES;

}

,则当节点达到100,再插入新节点就会删除过时的链表头部的节点。

LinkedHashMap提供了所有可选的Map操作,并允许插入null。因为要多维护一个链表,其性能可能略低于HashMap。但是,有一个例外:对LinkedHashMap的集合视图的迭代需要时间与map大小成正比,而不管其容量。 HashMap上的迭代可能会花销更大,需要的时间与其容量成正比。也就是说capacity 的大小对其性能影响没有对HashMap的大。

LinkedHashMap的实现是非同步的。当涉及到多个线程访问并且有线程改变其结构时,必须在外部进行同步。通常对使用map的对象进行同步来完成同步操作。如果不存在这样的对象,则应该使用Collections.synchronizedMap方法包裹该map。而且最好在创建时包裹,以防止不同步访问:

Map m = Collections.synchronizedMap(new LinkedHashMap(...));

这里,需要注意的是map节点的值改变不会导致结构改变,结构改变是指添加、删除节点或者修改顺序引起的改变。

LinkedHashMap继承了HashMap的fail-fast(快速失败)机制,该机制的实现是通过一个modCount变量来记录修改次数,在每次调用会导致LinkedHashMap结构改变的方法的时候就比较下理论上的修改次数和当前修改次数的值。如果相等则允许操作,并将modCount加1,如果不相等则抛出ConcurrentModificationException异常。这种机制只能用来检测错误,无法保证一定起效。

二、结构

LinkedHashMap之所以能够进行排序,是因为它在HashMap的“数组+链表”的结构上还维护了一个双向链表,其节点结构可以参考如下的图(这里重点关注before和after节点):

(图1)

整体结构可以参考如下的图(图上半部分的“数组+链表”结构继承自HashMap,绿色的箭头代表图1中的next,排序的实现主要通过下面的双向链表):

(图2来自:http://blog.csdn.net/luanlouis/article/details/43017071

三、源码分析

构造函数:

这里注意到第四个构造函数,如果指定第三个参数为true会开启按访问时间排序。另外几个构造函数都有设置accessOrder = false。

属性:

accessOrder已经说明过了。剩下的,head代表的是双向链表的头部,表示最久未被访问的节点。tail代表的是双向链表的尾部,表示最近一次访问的节点。

方法:

这里可以重点看下afterNodeAccess方法,调用put,putAll,putIfAbsent,get,getOrDefault,compute,computeIfAbsent,computeIfPresent或merge方法时都将调用该方法。而调用该方法时,如果accessOrder为true,且当前操作的节点在方法调用后存在,则会移动当前操作的节点至双向链表尾部。

void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}

其他方法介绍可参考:

http://blog.csdn.net/u014634338/article/details/78494051

四、总结

LinkedHashMap继承于 HashMap,相当于在HashMap的基础上添加了顺序访问的功能,而方法的操作也是基于HashMap之上,增加了对提供顺序访问功能的双向链表的维护。

LinkedHashMap学习的更多相关文章

  1. Java学习之LinkedHashMap学习总结

    前言: 在学习LRU算法的时候,看到LruCache源码实现是基于LinkedHashMap,今天学习一下LinkedHashMap的好处以及如何实现lru缓存机制的. 需求背景: LRU这个算法就是 ...

  2. Java LinkedHashMap学习

    以前一直使用HashMap,今天学习一下LinkedHashMap JavaDoc 注解: Hash table and linked list implementation of the Map i ...

  3. HashMap,TreeMap,LinkedHashMap学习

    Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复.Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快 ...

  4. java集合类学习笔记之LinkedHashMap

    1.简述 LinkedHashMap是HashMap的子类,他们最大的不同是,HashMap内部维护的是一个单向的链表数组,而LinkedHashMap内部维护的是一个双向的链表数组.HashMap是 ...

  5. JDK源码学习笔记——LinkedHashMap

    HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序. LinkedHashMap保证了元素迭代的顺序.该迭代顺序可以是插入顺序或者是访问顺序.通过维护一个 ...

  6. 【Java学习笔记】HashMap子接口---LinkedHashMap

    特点: 存入元素的顺序   与   取出元素的顺序相同(与LinkedHashSet类似) import java.util.HashMap; import java.util.Iterator; i ...

  7. LinkedHashMap源码学习

    描述 可以按照添加元素的顺序对元素进行迭代的HashMap的子类. 注意,上面说的是加元素的顺序.也就是说,更新元素时,是不会影响遍历结构的的.除非设置参数accessOrder为true,将更新元素 ...

  8. Java集合学习(5):LinkedHashMap

    一.概述 HashMap是无序的,HashMap在put的时候是根据key的hashcode进行hash然后放入对应的地方.所以在按照一定顺序put进HashMap中,然后遍历出HashMap的顺序跟 ...

  9. 学习JDK1.8集合源码之--LinkedHashMap

    1. LinkedHashMap简介 LinkedHashMap继承自HashMap,实现了Map接口. LinkedHashMap是HashMap的一种有序实现(多态,HashMap的有序态),可以 ...

随机推荐

  1. Xcode9 新功能

    翻译: https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/WhatsNewXcod ...

  2. [置顶] Isolation Forest算法实现详解

    本文算法完整实现源码已开源至本人的GitHub(如果对你有帮助,请给一个 star ),参看其中的 iforest 包下的 IForest 和 ITree 两个类: https://github.co ...

  3. C# OPC UA服务器 OPC UA网关 三菱 西门子 欧姆龙 Modbus转OPC UA 服务器 可配置的OPC UA服务器网关 HslSharp软件文档

    前言 本文将使用一个基于开源项目HslCommunication创建的OPC UA网关,方便通过配置创建一个OPC UA的网关中心.具体的操作及支持的设备信息项目参照下面: 开源项目HslCommun ...

  4. IOS开发 多线程GCD

    Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法. dispatch queue分成以下三种: 1)运行在主线程的Main queue,通过dispat ...

  5. 初用vue遇到的一些问题

    1.过滤器: filters: { search(list) { es5 var _self = this; //return list.filter(menu => menu.childs.n ...

  6. 【剑指offer】数组中的逆序对。C++实现

    原创文章,转载请注明出处! 博客文章索引地址 博客文章中代码的github地址 # 题目 # 思路 基于归并排序的思想统计逆序对:先把数组分割成子数组,再子数组合并的过程中统计逆序对的数目.统计逆序对 ...

  7. 【剑指offer】二叉树中和为某一值的路径,C++实现

    原创文章,转载请注明出处! 博客文章索引地址 1.题目 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径由结点和有向边组成,从根结点到叶节点. // 二叉树结点的定义 st ...

  8. 我在ubuntu14.04安装使用的软件

    搜狗拼音sougoupinyin:sudo add-apt-repository ppa:fcitx-team/nightly && sudo apt-get updatesudo a ...

  9. YUYV&YV12&mtk6763

    stImgInOut.stImgInfo.enImageType = UV_IMAGE_TYPE_YV12; stImgInOut.stImgInfo.as32Pitch[0] = pStreamIm ...

  10. git忽略已经提交的文件【转载】

    有时候我们添加.gitignore文件之前已经提交过了文件..gitignore只能忽略那些原来没有被track的文件(自添加以后,从未 add 及 commit 过的文件),如果某些文件已经被纳入了 ...