LinkedHashMap,根据插入值的顺序读取
key和value都可以为null,和hashmap相同

使用

        Map<String, String> linkedMap = new LinkedHashMap<String, String>();linkedMap.put("a", "1");linkedMap.put("d", "4");linkedMap.put("b", "2");linkedMap.put("c", "3");linkedMap.put("a", "10");linkedMap.remove("b");linkedMap.put("e", null);linkedMap.put(null, "f");System.out.println("LinkedHashMap:" + linkedMap);//LinkedHashMap:{a=10, d=4, c=3, e=null, null=f}

原理

LinkedHashMap,继承了HashMap。

public class LinkedHashMap<K,V>extends HashMap<K,V>implements Map<K,V>

HashMap为了避免碰撞,因此用拉链法解决冲突,HashMap中的连接只是同一个桶中的元素连接,而LinkedHashMap是将所有桶中的节点串联成一个双向链表。

它继承了HashMap的Node,Node基础上添加了before和after两个指针,构成了双向链表

 static class Entry<K,V> extends HashMap.Node<K,V> {Entry<K,V> before, after;Entry(int hash, K key, V value, Node<K,V> next) {super(hash, key, value, next);}}

LinkedHashMap使用的是LRU算法(Least Recently Used,最近最少使用) ,当你插入元素时它会将节点插入双向链表的链尾,如果key重复,则也会将节点移动至链尾,当用get()方法获取value时也会将节点移动至链尾。

构造方法,默认同hashmap一样,创建容量16,加载因子是0.75的数组,默认是插入顺序

//accessOrder默认为false,即按照插入顺序来连接,true则为按照访问顺序来连接public LinkedHashMap() {super();accessOrder = false;}

写入

LinkedHashMap使用HashMap的put方法,即使用hashmap的putVal()方法

if ((p = tab[i = (n - 1) & hash]) == null)//调用newNode()方法tab[i] = newNode(hash, key, value, null);else {

其创建节点的方法是newNode()方法,而LinkedHashMap重写了这个方法:

Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {LinkedHashMap.Entry<K,V> p =new LinkedHashMap.Entry<K,V>(hash, key, value, e);//将节点插入链尾linkNodeLast(p);return p;}private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {LinkedHashMap.Entry<K,V> last = tail;tail = p;// 如果链尾为空,则双向链表为空,则p即为头结点也为尾节点if (last == null)head = p;else {//否则的话修改指针,让之前链尾的after指针指向p,p的before指向之前链尾p.before = last;last.after = p;}}

插入新值时将其插入双向链表链尾,根据插入值得顺序,构成一个顺序链表

那么接下来put()更新值则节点移动至链尾怎么实现的呢?

if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;//在节点被访问后移动链尾afterNodeAccess(e);return oldValue;}}

如果是默认的插入顺序,此方法无效。如果是访问顺序,

void afterNodeAccess(Node<K,V> e) { // move node to lastLinkedHashMap.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;//如果前面没有元素,则p之前为头结点,直接让a成为头结点if (b == null)head = a;else// 否则b的尾指针指向ab.after = a;if (a != null)//如果a不为空,则a的头指针指向ba.before = b;else//否则 p之前就为尾指针,则另b成为尾指针last = b;if (last == null)//如果双向链表中只有p一个节点,则令p即为头结点,也为尾节点head = p;else {//否则 将p插入链尾p.before = last;last.after = p;}tail = p;++modCount;}}

此外HashMap的putVal()方法,还调用了afterNodeInsertion()方法,

        ++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);return null;

LinkedHashMap重写了afterNodeInsertion方法,不过removeEldestEntry()默认是返回false的,需要子类继承重写removeEldestEntry()方法。

void afterNodeInsertion(boolean evict) { // possibly remove eldestLinkedHashMap.Entry<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;}

删除

调用的HashMap的remove()方法

  public V remove(Object key) {Node<K,V> e;return (e = removeNode(hash(key), key, null, false, true)) == null ?null : e.value;}

removeNode方法中

//回调从双向链表中移除nodeafterNodeRemoval(node);return node;}}return null;}

LinkedHashMap重写了afterNodeRemoval方法

void afterNodeRemoval(Node<K,V> e) { // unlinkLinkedHashMap.Entry<K,V> p =(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;p.before = p.after = null;if (b == null)head = a;elseb.after = a;if (a == null)tail = b;elsea.before = b;}

读取

LinkedHashMap重写了get()方法,实现了LRU

public V get(Object key) {Node<K,V> e;if ((e = getNode(hash(key), key)) == null)return null;// accessOder为true时,被访问的节点被置于双向链表尾部if (accessOrder)afterNodeAccess(e);return e.value;}

遍历

LinkedHashIterator() {next = head;expectedModCount = modCount;current = null;}public final boolean hasNext() {return next != null;}final LinkedHashMap.Entry<K,V> nextNode() {LinkedHashMap.Entry<K,V> e = next;if (modCount != expectedModCount)throw new ConcurrentModificationException();if (e == null)throw new NoSuchElementException();current = e;next = e.after;return e;}

从头结点开始,向后开始遍历

JDK1.8 LinkedHashMap源码相关推荐

  1. linkedHashMap源码解析(JDK1.8)

    引言 关于java中的不常见模块,让我一下子想我也想不出来,所以我希望以后每次遇到的时候我就加一篇.上次有人建议我写全所有常用的Map,所以我研究了一晚上LinkedHashMap,把自己感悟到的解释 ...

  2. Java8 LinkedHashMap 源码阅读

    如果你对 HashMap 的源码有了解的话,只需要一图就能知道 LinkedHashMap 的原理了,但是具体的实现细节还是需要去读一下源码. 一.LinkedHashMap 简介 1.1 继承结构 ...

  3. Java类集框架 —— LinkedHashMap源码分析

    前言 我们知道HashMap底层是采用数组+单向线性链表/红黑树来实现的,HashMap在扩容或者链表与红黑树转换过程时可能会改变元素的位置和顺序.如果需要保存元素存入或访问的先后顺序,那就需要采用L ...

  4. jdk1.8.0_45源码解读——Map接口和AbstractMap抽象类的实现

    jdk1.8.0_45源码解读--Map接口和AbstractMap抽象类的实现 一. Map架构 如上图: (01) Map 是映射接口,Map中存储的内容是键值对(key-value). (02) ...

  5. LinkedHashMap源码剖析

    1. LinkedHashMap简介 LinkedHashMap是HashMap的子类,与HashMap有着同样的存储结构,但它加入了一个双向链表的头结点,将所有put到LinkedHashmap的节 ...

  6. 转:【Java集合源码剖析】LinkedHashmap源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/37867985   前言:有网友建议分析下LinkedHashMap的源码,于是花了一晚上时 ...

  7. jdk1.8.0_45源码解读——Set接口和AbstractSet抽象类的实现

    jdk1.8.0_45源码解读--Set接口和AbstractSet抽象类的实现 一. Set架构 如上图: (01) Set 是继承于Collection的接口.它是一个不允许有重复元素的集合. ( ...

  8. jdk1.8.0_45源码解读——ArrayList的实现

    转载自  jdk1.8.0_45源码解读--ArrayList的实现 一.ArrayList概述 ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括 null 在内的 ...

  9. Jdk1.8 JUC源码增量解析(1)-atomic-Striped64

    转载自  Jdk1.8 JUC源码增量解析(1)-atomic-Striped64 功能简介: Striped64是jdk1.8提供的用于支持如Long累加器,Double累加器这样机制的基础类. S ...

最新文章

  1. 动态增删表格行(纯JS写法)
  2. 97页PPT,读懂自动驾驶全产业链发展!
  3. Java 面向对象 之 引用传递
  4. 计算机体系结构 第一章
  5. 明科在线客服系统PHP_在线客服系统的标准功能有哪些
  6. 正睿2019省选附加赛 Day10 (这篇其实已经都咕咕了...)
  7. weblogic问题: Unable to resolve 'jdbc.mydb'. Resolved 'jdbc'; remaining name '
  8. Mysql-元数据的查询/case when配合聚合函数的技巧
  9. oracle 快速关闭_快速关闭
  10. 机载激光雷达原理与应用科普(九)
  11. pandas(一) Series和DataFrame
  12. win7安装打印机 计算机,Win7如何安装网络打印机丨Win7安装网络打印机解决方法...
  13. APP上架各大应用市场对比
  14. 一文解读时间序列基本概念
  15. 每日五题 -202110
  16. ltb火箭_火箭的大脑
  17. Navicat11 for mysql(包括激活工具)亲测可用
  18. bert 中文 代码 谷歌_从字到词,大词典中文BERT模型的探索之旅
  19. 【iOS开发】AFNetworking上传语音文件(.mp3)到服务器
  20. 网易、腾讯、阿里竞相押宝的NFT,还有多大的想象空间?

热门文章

  1. JavaScript学习(六十五)—数组知识点总结
  2. 力扣 两个数组的交集
  3. 桌面 NAS 是什么
  4. 如果手里有20万是放银行吃利息还是投资比较合适?
  5. 女婿的行为,老丈人哪些不能管,哪些必须管,哪些可管可不管?
  6. 头条鼓励内容营销吗?创作商品营销内容会不会限制推荐?
  7. 每个时代都有每个时代的风口
  8. 实体经济不改变经营思路和销售模式
  9. 5G的基站覆盖范围300米,今后边远地区的手机通话怎样保证?
  10. JDK和IDEA的安装(JDK11及以上版本自带JRE)