【源码】LinkedHashMap源码剖析
来源:互联网 发布:二叉树的前序遍历java 编辑:程序博客网 时间:2024/04/20 01:10
注:以下源码基于jdk1.7.0_11
之前的两篇文章通过源码分析了两种常见的Map集合,HashMap和Hashtable。本文将继续介绍另一种Map集合——LinkedHashMap。
顾名思义,LinkedHashMap除了是一个HashMap之外,还带有LinkedList的特点,也就是说能够保持遍历的顺序和插入的顺序一致,那么它是怎么做到的呢?
下面我们开始分析。
首先看构造器。
LinkedHashMap直接继承自HashMap,所以拥有HashMap的大部分特性,
比如支持null键和值,默认容量为16,装载因子为0.75,非线程安全等等。
但是LinkedHashMap还有很多个性的地方,
下面来看成员变量:
LinkedHashMap比HashMap多了两个成员变量,
其中header代表内部双向链表的头结点,
后面我们就会发现,LinkedHashMap除了有个桶数组容纳所有Entry之外,还有一个双向链表保存所有Entry引用。
遍历的时候,并不是去遍历桶数组,而是直接遍历双向链表,
所以LinkedHashMap的遍历时间不受桶容量的限制,这是它和HashMap的重要区别之一。
而这个accessOrder代表的是是否按照访问顺序,true代表是,默认是插入顺序。
所以我们可以将accessOrder置为true来实现LRU算法,这可以用来做缓存。
再看构造器:
构造器首先都会调用父类也就是HashMap的构造器来初始化桶数组,
而accessOrder之后会被初始化,
除了最后面的一个构造器允许指定accessOrder外,
其他构造器都默认将accessOrder置为了false。
读者可能很奇怪,不是还有个header么,这个双向链表为啥不在构造器中初始化呢?
这得回到HashMap中查看hashMap的构造器了:
HashMap构造器最后一步调用了一个init方法,而这个init方法在HashMap中是个空实现,没有任何代码。
这其实就是所谓的“钩子”,
具体代码由子类实现,
如果子类希望每次构造的时候都去做一些特定的初始化操作,
可以选择复写init方法。
我们看到LinkedHashMap中确实复写了init:
在init方法中,果然初始化了双向链表,而且我们还发现,这不光是个双向链表,还是个循环链表。
HashMap内部的Entry类并没有before和after指针,
也就是说LinkedHashMap自己重写了一个Entry类:
这里的Entry选择继承父类的Entry类,
也就是说LinkedHashMap中的Entry拥有三个指针,
除了前驱后继指针外用于双向链表的连接外,
还有一个next指针用于解决hash冲突(引用链)。
除此之外,Entry新增了几个方法,remove和addbefore用来操作双向链表不用多说。
而recordAccess方法比较特殊,这个方法在HashMap中也是空实现,并在put方法中会调用此方法:
此外,在LinkedHashMap的get方法中,也会调用此方法:
也就是说,只要涉及到访问结点,那么就会调用这个方法。
观察该方法的逻辑:
如果accessOrder为true,
那么会调用addBefore方法将当前Entry放到双向链表的尾部,
最终在我们遍历链表的时候就会发现最近最少使用的结点的都集中在链表头部(从近期访问最少到近期访问最多的顺序),
这就是LRU。
LinkedHashMap并没有复写put方法,
但是却复写了addEntry和createEntry方法,
之前分析HashMap的时候我们就知道了,
put方法会调用addEntry将键值对挂到桶的某个合适位置,
而addEntry又会调用createEntry方法创建一个键值对对象。
因而,LinkedHashMap其实是间接更改了put方法,
想想也很容易理解,LinkedHashMap除了要向桶中添加键值对外,
还需向链表中增加键值对,所以必须得修改put方法。
createEntry方法会将键值对分别挂到桶数组和双向链表中。
比较有意思的是addEntry方法,它提供了一个可选的操作,
我们可以通过继承LinkedHashMap并复写removeEldestEntry方法,
让该子类可以自动地删除最近最少访问的键值对——这可以用来做缓存!!
LinkedHashMap自定义了迭代器以及迭代规则,
LinkedHashMap是通过内部的双向链表来完成迭代的,
遍历时间与键值对总数成正比,而HashMap遍历时间与容量成正比,
所以通常情况下,LinkedHashMap遍历性能是优于HashMap的,
但是因为需要额外维护链表,所以折中来看,两者性能相差无几。
总结:
1.LinkedHashMap继承自HashMap,具有HashMap的大部分特性,
比如支持null键和值,默认容量为16,装载因子为0.75,非线程安全等等;
2.LinkedHashMap通过设置accessOrder控制遍历顺序是按照插入顺序还是按照访问顺序。
当accessOrder为true时,可以利用其完成LRU缓存的功能;
3.LinkedHashMap内部维护了一个双向循环链表,并且其迭代操作时通过链表完成的,而不是去遍历hash表。
原文地址:http://blog.csdn.net/chdjj/article/details/38677315
0 0
- 【源码】LinkedHashMap源码剖析
- 【源码】LinkedHashMap源码剖析
- LinkedHashMap源码剖析
- LinkedHashMap 源码剖析
- LinkedHashMap源码剖析
- Java LinkedHashMap 源码剖析
- LinkedHashMap源码剖析
- LinkedHashmap源码剖析
- 【Java集合源码剖析】LinkedHashmap源码剖析
- 【Java集合源码剖析】LinkedHashmap源码剖析
- 【Java集合源码剖析】LinkedHashmap源码剖析
- 【Java集合源码剖析】LinkedHashmap源码剖析
- 【Java集合源码剖析】LinkedHashmap源码剖析
- 【Java集合源码剖析】LinkedHashmap源码剖析
- 【Java集合源码剖析】LinkedHashmap源码剖析
- 【Java集合源码剖析】LinkedHashmap源码剖析
- 【Java集合源码剖析】LinkedHashmap源码剖析
- 源码剖析——LinkedHashMap
- 与轮播图结合的ViewPagerIndicatorView
- 继承
- 【Codeforces】-629B-.Far Relative’s Problem(贪心.时间区间)
- Cow Contest(Floyd)
- codeforces #300 E. Demiurges Play Again(tree DP)
- 【源码】LinkedHashMap源码剖析
- (一)Spring框架——概览
- 安装,卸载WPS-office报错,如何解决?
- java根据后台查询结果合并list
- UIWebView的简单使用
- 经验分享之搭建SVN服务器问题集锦
- 【杭电1070】milk (sort+结构体)
- Python3 使用bs4按标签提取贴吧楼主发表内容
- Anroid之HttpClient异步请求数据