博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java集合之LinkedHashMap
阅读量:5116 次
发布时间:2019-06-13

本文共 3593 字,大约阅读时间需要 11 分钟。

我们在使用HashMap的过程中会发现一个问题,对于这个集合,我们好像没有办法让其按照我们想要的顺序输出。

针对这个需求,就诞生了LinkedHashMap。

LinkedHashMap集成了HashMap,然后有两个自己的独特成员:

private transient Entry
header;private final boolean accessOrder;

LinkedList是一个双向链表,header是其头部,是一个初始化为-1的节点,这也是一个链表常见的技巧。

void init() {    header = new Entry<>(-1, null, null, null);    header.before = header.after = header;}

而这位accessOrder同学就是主角啦!

对LinkedHashMap初始化时,可以选择是否初始化这个成员,

public LinkedHashMap(int initialCapacity, float loadFactor) {    super(initialCapacity, loadFactor);    accessOrder = false;}public LinkedHashMap(int initialCapacity) {    super(initialCapacity);    accessOrder = false;}public LinkedHashMap() {    super();    accessOrder = false;}public LinkedHashMap(Map
m) { super(m); accessOrder = false;}public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder;}
View Code

如果不初始化,则默认是false,此时保持放入元素先后的顺序不变化,即按照你插入的顺序排列和输出。

如果选择初始化为true,则按照访问顺序排列。

从get操作中可以验证这个结论

public V get(Object key) {    Entry
e = (Entry
)getEntry(key); if (e == null) return null; e.recordAccess(this); return e.value;}

看一下recordAccess()函数,这是Entry的方法:

void recordAccess(HashMap
m) { LinkedHashMap
lm = (LinkedHashMap
)m; if (lm.accessOrder) { lm.modCount++; remove(); addBefore(lm.header); }}

如果LinkedHashMap的accessOrder为true,就先remove,然后添加到双向链表的尾部(双向链表header的before节点就是末尾节点),这样就完成了按访问顺序排列

至于Entry内部的操作,例如添加、删除之类的,就是简单的双向链表操作的方法,直接上代码了,折叠之:

private static class Entry
extends HashMap.Entry
{ // These fields comprise the doubly linked list used for iteration. Entry
before, after; Entry(int hash, K key, V value, HashMap.Entry
next) { super(hash, key, value, next); } /** * Removes this entry from the linked list. */ private void remove() { before.after = after; after.before = before; } /** * Inserts this entry before the specified existing entry in the list. */ private void addBefore(Entry
existingEntry) { after = existingEntry; before = existingEntry.before; before.after = this; after.before = this; } /** * This method is invoked by the superclass whenever the value * of a pre-existing entry is read by Map.get or modified by Map.set. * If the enclosing Map is access-ordered, it moves the entry * to the end of the list; otherwise, it does nothing. */ void recordAccess(HashMap
m) { LinkedHashMap
lm = (LinkedHashMap
)m; if (lm.accessOrder) { lm.modCount++; remove(); addBefore(lm.header); } } void recordRemoval(HashMap
m) { remove(); }}
View Code

 上面看的是访问节点,那么添加节点呢?

void addEntry(int hash, K key, V value, int bucketIndex) {    super.addEntry(hash, key, value, bucketIndex);    // Remove eldest entry if instructed    Entry
eldest = header.after; if (removeEldestEntry(eldest)) { removeEntryForKey(eldest.key); }}

直接继承HashMap的添加节点方法,但下面又调用了一个删除最老节点的操作,看一下:

protected boolean removeEldestEntry(Map.Entry
eldest) { return false;}

咦?那这样不是永远都返回false么?哪还有什么意义?

当然有意义,我们可以重写这个函数,为期设定删除最老节点的条件,例如size()>100之类的。

到这里,应该就意识到了,这个LinkedHashMap好像可以实现鼎鼎大名的LRU缓存算法吧?答对了,不过这个在以后细说。

好了,LinkedHashMap的分析暂时就到这里。

转载于:https://www.cnblogs.com/yueyanglou/p/5256146.html

你可能感兴趣的文章
@property中 retain 详解
查看>>
uva 387 A Puzzling Problem (回溯)
查看>>
12.2日常
查看>>
Delphi 取整函数round、trunc、ceil和floor
查看>>
C/C++二维数组的用法
查看>>
排序 冒泡排序法
查看>>
同步代码时忽略maven项目 target目录
查看>>
MVC.NET:提供对字体文件.woff的访问
查看>>
Informatica_(2)第一个例子
查看>>
string 常用函数
查看>>
RGB色彩的计算机表示
查看>>
iOS地图之MapKit框架
查看>>
2010年过年左右时的艾米果
查看>>
朱元璋
查看>>
Oracle中包的创建
查看>>
python入门_老男孩_数据类型简介_int/bool/str转换_字符串索引和切片_字符串操作_day3...
查看>>
mysql 查询之聚合查询
查看>>
关于χ²分布和统计
查看>>
[sublime] sublime 实现Markdown编辑器
查看>>
【洛谷1962】 斐波那契数列
查看>>