LinkedHashMap源码解析
转载请以链接形式标明出处: 本文出自:103style的博客
base on jdk_1.8.0_77
目录
LinkedHashMap
简介LinkedHashMap
的全局变量介绍LinkedHashMap
的构造函数LinkedHashMap
重写的函数- 小结
- 参考文章
LinkedHashMap简介
HashMap
是无序的,HashMap
在 put
的时候是根据 key
的 hashcode
进行 hash
然后放入对应的地方。所以在按照一定顺序 put
进 HashMap
中,然后遍历出 HashMap
的顺序跟 put
的顺序不同。
class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>
LinkedHashMap
是 HashMap
的子类。它保留插入的顺序,如果需要输出的顺序和输入时的相同,那么就选用 LinkedHashMap
。
LinkedHashMap
是 Map
接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现提供所有可选的映射操作,并允许使用 null值
和 null键
。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
LinkedHashMap
实现与 HashMap
的不同之处在于,LinkedHashMap
维护着一个运行于所有条目的 双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。
注意,此实现不是同步的。如果多个线程同时访问链接的哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须保持外部同步。
根据链表中元素的顺序可以分为:按插入顺序的链表,和 按访问顺序(调用 get 方法
) 的链表。默认是按插入顺序排序,如果指定按访问顺序排序,那么调用get
方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。
LinkedHashMap的全局变量介绍
transient LinkedHashMapEntry<K,V> head;
双向链表的头节点
transient LinkedHashMapEntry<K,V> tail;
双向链表的尾节点
final boolean accessOrder;
false
:按插入顺序排序true
:按访问顺序排序
LinkedHashMapEntry
在HashMap.Node
的基础上添加了 before
和after
节点在实现双向链表。
static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> {
LinkedHashMapEntry<K,V> before, after;
LinkedHashMapEntry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
LinkedHashMap的构造函数
相比HashMap来说,只是添加了accessOrder
默认为false
,以及可以设置accessOrder
的构造函数。
public LinkedHashMap() {
super();
accessOrder = false;
}
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;
}
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
putMapEntries(m, false);
}
public LinkedHashMap(int initialCapacity, float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
LinkedHashMap重写的函数
LinkedHashMap
重写了HashMap
的以下方法来实现按对应排序输出。
afterNodeAccess(Node<K,V> p)
:数据访问之后afterNodeInsertion(boolean evict)
:数据插入完成之后afterNodeRemoval(Node<K,V> p)
:数据移除之后get(Object key)
andgetOrDefault(Object key, V defaultValue)
afterNodeAccess
- 如果时按访问顺序排序的话(
accessOrder = true
),并且当前节点不是尾节点,则将当前节点移动到双向链表末端
void afterNodeAccess(Node<K, V> e) {
LinkedHashMapEntry<K, V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMapEntry<K, V> p =
(LinkedHashMapEntry<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;
}
}
afterNodeInsertion
- 因为
removeEldestEntry
返回false
所以啥也没做.
void afterNodeInsertion(boolean evict) {
LinkedHashMapEntry<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;
}
afterNodeRemoval
- 即删除双向队列中的节点
void afterNodeRemoval(Node<K, V> e) {
LinkedHashMapEntry<K, V> p =
(LinkedHashMapEntry<K, V>) e, b = p.before, a = p.after;
p.before = p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a == null)
tail = b;
else
a.before = b;
}
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;
}
public V getOrDefault(Object key, V defaultValue) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return defaultValue;
if (accessOrder)
afterNodeAccess(e);
return e.value;
}
小结
LinkedHashMap
只是在HashMap
的基础上维护了一个双向链表来保证按accessOrder
对应的顺序来输出。- 在每次数据操作之后都会修改双向链表来保证对应的顺序。
参考文章
以上
相关文章
- 安卓电影购票选座APP源码
- recyclerView源码解析
- 源码编译安装grafana
- 【说站】某鱼最近卖的很火的蓝色版去水印小程序源码+接口
- react源码分析:babel如何解析jsx
- Juc并发编程12——2万字深入源码:线程池这篇真的讲解的透透的了
- Zookeeper之FileSnap源码分析
- react源码解析11.生命周期调用顺序_2023-02-28
- Java中Thread.sleep源码分析
- 【TarsosDSP】TarsosDSP 简介 ( TarsosDSP 功能 | 相关链接 | 源码和相关资源收集 | TarsosDSP 示例应用 | TarsosDSP 源码路径解析 )
- 【Android 异步操作】AsyncTask 异步任务 ( AsyncTask 异步任务执行方法 execute 方法相关源码解析 )
- 【Android 异步操作】Handler 机制 ( Android 提供的 Handler 源码解析 | Handler 构造与消息分发 | MessageQueue 消息队列相关方法 )
- SkeyeLive开源流媒体同屏直播软件源码功能框架解析
- SkeyePlayer渲染引擎D3DRender电子放大功能实现解决方案(附源码) (1)
- 使用make编译源码,使用-j 参数的作用详解程序员
- kafka源码解析之六SocketServer详解编程语言
- 探究Linux内核启动:源码解析与应用实践(linux内核启动源码)
- 源码解析研究MySQL搭配CAS的可能性(cas 源码mysql)