特点

* 各个元素不仅仅按照HashMap的结构存储,而且每个元素包含了before/after指针,通过一个头元素header,形成一个双向循环链表。使用循环链表,保存了元素插入的顺序。
* 可设置参数,让每次get()后的元素排在双向链表的最后。
 
Entry类
private static class Entry<K,V> extends HashMap.Entry<K,V> // 继承自HashMap的Entry(已有key/value/hash/next字段)
{
// 双向链表
Entry<K,V> before;
Entry<K,V> after; // 构造函数
Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
super(hash, key, value, next);
} // 删除当前结点
private void remove(){
before.after = after;
after.before = before;
} // 在当前结点的前面添加结点
private void addBefore(Entry<K,V> existingEntry){
after = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
} // 如果设定某个参数,get()命中后,把当前元素放到链表最后
void recoreAccess(HashMap<K,V> m) {
LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; // 把调用者的this转化成LinkedHashMap
if(lm.accessOrder){
remove(); // 删除当前结点
addBefore(lm.header); // 插入到header前面
}
}
}

  

源码简要分析

public class LinkedHashMap<K,V> extends HashMap<K,V>
{
private Entry<K,V> header; // 双向链表的头部。
private final boolean accessOrder; // 默认false。如果true表示get()命中后,把当前元素放到链表最后。 // init()
void init() {
header = new Entry<>(-1, null, null, null);
header.before = header.after = header; // 双向链表首尾相连
} // put() 继承自 HashMap
// 添加元素时,不仅按照HashMap的方式散列存储,而且还通过双向链表记录先后顺序
public V put(K key, V value) {
int hash = hash(key.hashCode()); // key的特殊hash值
int i = indexFor(hash,table.length); // 槽位 index // key是否已经存在,存在则返回value。
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this); //LinkedHashMap特有
return oldValue;
}
} // key不存在就添加Entry
addEntry(hash,key,value,i);
return null;
} void addEntry(int hash, K key, V value, int bucketIndex) {
createEntry(hash, key, value, bucketIndex); // Remove eldest entry if instructed, else grow capacity if appropriate
Entry<K,V> eldest = header.after;
if (removeEldestEntry(eldest)) {
removeEntryForKey(eldest.key);
} else {
if (size >= threshold)
resize(2 * table.length);
}
} void createEntry(int hash, K key, V value, int bucketIndex/*槽位index*/) {
HashMap.Entry<K,V> old = table[bucketIndex];
Entry<K,V> e = new Entry<>(hash, key, value, old);
table[bucketIndex] = e;
e.addBefore(header);
size++;
} // get()
// 取元素是按照散列而不是双向链表进行查找,速度快
public V get(Object key) {
Entry<K,V> e = (Entry<K,V>)getEntry(key); // getEntry()使用了HashMap的getEntry,即按照HashMap的方式寻找元素。
if (e == null)
return null;
e.recordAccess(this);
return e.value;
} }

  

添加元素的过程示意图

初始化时,头元素header的before/after均指向自身。

插入元素e1后,header的before/after均指向e1;e1的before/after均指向header。

插入元素e2后,header的after继续指向e1,e1的after指向e2,e1的before指向header。header的before指向e2。e2的before指向e1,e2的after指向header。

[Java] LinkedHashMap 源码简要分析的更多相关文章

  1. [Java] Hashtable 源码简要分析

    Hashtable /HashMap / LinkedHashMap 概述 * Hashtable比较早,是线程安全的哈希映射表.内部采用Entry[]数组,每个Entry均可作为链表的头,用来解决冲 ...

  2. [Java] HashMap 源码简要分析

    特性 * 允许null作为key/value. * 不保证按照插入的顺序输出.使用hash构造的映射一般来讲是无序的. * 非线程安全. * 内部原理与Hashtable类似.   源码简要分析 pu ...

  3. RxJava && Agera 从源码简要分析基本调用流程(2)

    版权声明:本文由晋中望原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/124 来源:腾云阁 https://www.qclo ...

  4. Activity源码简要分析总结

    Activity源码简要分析总结 摘自参考书籍,只列一下结论: 1. Activity的顶层View是DecorView,而我们在onCreate()方法中通过setContentView()设置的V ...

  5. LinkedHashMap 源码详细分析(JDK1.8)

    1. 概述 LinkedHashMap 继承自 HashMap,在 HashMap 基础上,通过维护一条双向链表,解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题.除此之外,Linke ...

  6. Java——LinkedHashMap源码解析

    以下针对JDK 1.8版本中的LinkedHashMap进行分析. 对于HashMap的源码解析,可阅读Java--HashMap源码解析 概述   哈希表和链表基于Map接口的实现,其具有可预测的迭 ...

  7. java Linkedhashmap源码分析

    LinkedHashMap类似于HashMap,但是迭代遍历它时,取得“键值对”的顺序是插入次序,或者是最近最少使用(LRU)的次序.只比HashMap慢一点:而在迭代访问时反而更快,因为它使用链表维 ...

  8. RxJava && Agera 从源码简要分析基本调用流程(1)

    版权声明:本文由晋中望原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/123 来源:腾云阁 https://www.qclo ...

  9. Elasticsearch之client源码简要分析

    问题 让我们带着问题去学习,效率会更高 1  es集群只配置一个节点,client是否能够自动发现集群中的所有节点?是如何发现的? 2  es client如何做到负载均衡? 3  一个es node ...

随机推荐

  1. php中foreach()跳出循环或者终止循环的实现方法

    $arr = array('a','b','c','d','e'); $html = ''; foreach($arr as $key => $value){ if($value=='b'){ ...

  2. HRBUST - 1818 石子合并 区间dp入门

    有点理解了进阶指南上说的”阶段,状态和决策“ /* 区间dp的基础题: 以区间长度[2,n]为阶段,枚举该长度的区间,状态dp[l][r]表示合并区间[l,r]的最小费用 状态转移方程dp[l][r] ...

  3. 数论知识点总结(noip范围)

    数论知识点: 约数个数和约数和公式(例题:POJ1845 分治思想): 质因数分解 p1^k1xp2^k2xp3^k3...pn^kn 约数个数和:(1+k1)(1+k2)...(1+kn) 所有约数 ...

  4. 详解如何在 Linux 中安装最新的 Python 3.6 版本

    # 下载源码包安装,先装wget,或curl. yum install wget # 再安装解压缩和编译环境: yum install zlib-devel bzip2-devel openssl-d ...

  5. wxpython安装,demo下载

    wxPython介绍      wxPython是Python语言的一套优秀的GUI图形库.wxPython可以很方便的创建完整的.功能键全的GUI用户界面. wxPython安装 本安装采用pip自 ...

  6. 《Android进阶之光》--网络编程与网络框架

    No1: Volley源码分析: Volley.newRequestQueue-> RequestQueue.start()-> CacheDispatcher.start()->C ...

  7. HihoCoder - 1078 【区间修改】

    题目链接:https://vjudge.net/contest/241135#problem/A 题目大意:(与区间修改模板题相同) 输入 每个测试点(输入文件)有且仅有一组测试数据. 每组测试数据的 ...

  8. WebPack 学习:从阮神的15个DEMO开始

    WebPack 是什么 官方就一句话,打包所有的资源. 从阮神的 15 DEOM入手 Webpack Github 地址 阮神GIT 按照 ReadME 操作 npm webpack-dev-serv ...

  9. js基础梳理-究竟什么是变量对象,什么是活动对象?

    首先,回顾下上篇博文中js基础梳理-究竟什么是执行上下文栈(执行栈),执行上下文(可执行代码)?的执行上下文的生命周期: 3.执行上下文的生命周期 3.1 创建阶段 生成变量对象(Variable o ...

  10. ubuntu安装nodejs出现./config.gypi错误

    报错的内容如下: xxx@xxx [/usr/local/src/node-v0.8.3]# ./configure { 'target_defaults': { 'cflags': [], 'def ...