LinkedHashMap

上两篇文章讲了HashMap,HashMap是一种非常常见、非常有用的集合,并且在多线程情况下使用不当会有线程安全问题。

不过HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序。

这个时候,LinkedHashMap就闪亮登场了,它虽然增加了时间和空间上的开销,但是通过维护一个运行于所有条目的双向链表,LinkedHashMap保证了元素迭代的顺序

四个关注点在LinkedHashMap上的答案

关 注 点 结 论
LinkedHashMap是否允许键值对为空 Key和Value都允许空
LinkedHashMap是否允许重复数据 Key重复会覆盖、Value允许重复
LinkedHashMap是否有序 有序
LinkedHashMap是否线程安全 非线程安全

LinkedHashMap基本数据结构

关于LinkedHashMap,先提两点:

1、LinkedHashMap可以认为是HashMap+LinkedList,即它既使用HashMap操作数据结构,又使用LinkedList维护插入元素的先后顺序

2、LinkedHashMap的基本实现思想就是----多态。可以说,理解多态,再去理解LinkedHashMap原理会事半功倍;反之也是,对于LinkedHashMap原理的学习,也可以促进和加深对于多态的理解

private static class Entry<K,V> extends HashMap.Entry<K,V> {    // These fields comprise the doubly linked list used for iteration.    Entry<K,V> before, after;​Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {        super(hash, key, value, next);   }   ...}

列一下Entry里面有的一些属性吧:

  • K key

  • V value

  • Entry<K, V> next

  • int hash

  • Entry<K, V> before

  • Entry<K, V> after

其中前面四个,也就是红色部分是从HashMap.Entry中继承过来的;后面两个,也就是蓝色部分是LinkedHashMap独有的。不要搞错了next和before、After,next是用于维护HashMap指定table位置上连接的Entry的顺序的,before、After是用于维护Entry插入的先后顺序的

还是用图表示一下,列一下属性而已:

LinkedHashMap添加元素

继续看LinkedHashMap添加元素,也就是put("111","111")做了什么,首先当然是调用HashMap的put方法:

继续看LinkedHashMap添加元素,也就是put("111","111")做了什么,首先当然是调用HashMap的put方法:

 1 public V put(K key, V value) { 2     if (key == null) 3         return putForNullKey(value); 4     int hash = hash(key.hashCode()); 5     int i = indexFor(hash, table.length); 6     for (Entry<K,V> e = table[i]; e != null; e = e.next) { 7         Object k; 8         if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 9             V oldValue = e.value;10             e.value = value;11             e.recordAccess(this);12             return oldValue;13         }14     }15 16     modCount++;17     addEntry(hash, key, value, i);18     return null;19 }

第17行又是一个多态,因为LinkedHashMap重写了addEntry方法,因此addEntry调用的是LinkedHashMap重写了的方法:

 1 void addEntry(int hash, K key, V value, int bucketIndex) { 2     createEntry(hash, key, value, bucketIndex); 3  4     // Remove eldest entry if instructed, else grow capacity if appropriate 5     Entry<K,V> eldest = header.after; 6     if (removeEldestEntry(eldest)) { 7         removeEntryForKey(eldest.key); 8     } else { 9         if (size >= threshold)10             resize(2 * table.length);11     }12 }

因为LinkedHashMap由于其本身维护了插入的先后顺序,因此LinkedHashMap可以用来做缓存,第5行~第7行是用来支持FIFO算法的,这里暂时不用去关心它。看一下createEntry方法:

1 void createEntry(int hash, K key, V value, int bucketIndex) {2     HashMap.Entry<K,V> old = table[bucketIndex];3     Entry<K,V> e = new Entry<K,V>(hash, key, value, old);4     table[bucketIndex] = e;5     e.addBefore(header);6     size++;7 }
private void addBefore(Entry<K,V> existingEntry) {    after  = existingEntry;    before = existingEntry.before;    before.after = this;    after.before = this;}

第2行~第4行的代码和HashMap没有什么不同,新添加的元素放在table[i]上,差别在于LinkedHashMap还做了addBefore操作,这四行代码的意思就是让新的Entry和原链表生成一个双向链表。假设字符串111放在位置table[1]上,生成的Entry地址为0x00000001,那么用图表示是这样的:

如果熟悉LinkedList的源码应该不难理解,还是解释一下,注意下existingEntry表示的是header:

1、after=existingEntry,即新增的Entry的after=header地址,即after=0x00000000

2、before=existingEntry.before,即新增的Entry的before是header的before的地址,header的before此时是0x00000000,因此新增的Entry的before=0x00000000

3、before.after=this,新增的Entry的before此时为0x00000000即header,header的after=this,即header的after=0x00000001

4、after.before=this,新增的Entry的after此时为0x00000000即header,header的before=this,即header的before=0x00000001

这样,header与新增的Entry的一个双向链表就形成了。再看,新增了字符串222之后是什么样的,假设新增的Entry的地址为0x00000002,生成到table[2]上,用图表示是这样的:

就不细解释了,只要before、after清除地知道代表的是哪个Entry的就不会有什么问题。

总得来看,再说明一遍,LinkedHashMap的实现就是HashMap+LinkedList的实现方式,以HashMap维护数据结构,以LinkList的方式维护数据插入顺序。

转载于:https://www.cnblogs.com/create-and-orange/p/11237072.html

LinkedHashMap相关推荐

  1. LinkedHashMap and LinkedHashSet

    LinkedHashMap实现了Map接口,是HashMap的直接子类,它同时满足HashMap和linked list的某些特性.可将LinkedHashMap看作采用linked list增强的H ...

  2. LInkedHashMap实现最近被使用(LRU)缓存

    在最近的面试中,我曾被多次问到,怎么实现一个最近最少使用(LRU)的缓存.缓存可以通过哈希表来实现,然而为这个缓存增加大小限制会变成另一个有意思的问题.现在我们看一下怎么实现. 最近最少使用缓存的回收 ...

  3. 彻底理解HashMap及LinkedHashMap

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:https://blog.csdn.net/fuzhongmin05/article/details/104355841 Ha ...

  4. HashMap和LinkedHashMap的区别

    转自:https://www.cnblogs.com/yuexzh/p/7486264.html HashMap,LinkedHashMap,TreeMap都属于Map Map 主要用于存储键(key ...

  5. linkedhashmap 顺序_有关于LinkedHashMap一份简单理解

    / 今日科技快讯 / 近日,台湾地区媒体<经济日报>转引<日经亚洲评论>报道称,自去年起,已有100多位原台积电工程师和经理人员被挖角到中国大陆,从事芯片研发制造项目.对此台积 ...

  6. HashTable, HashMap, LinkedHashMap, ConcurrentHashMap

    HashTable: 不允许null的key或value, 线程安全 HashMap: 允许一个null的key, 无限的null value, 非线程安全 LinkedHashMap: HashMa ...

  7. HashMap,LinkedHashMap,TreeMap的有序性

    HashMap 是将 Key 做 Hash 算法,然后将 Hash 值映射到内存地址,直接取得 Key 所对应的数据.在 HashMap 中,底层数据结构使用的是数组,所谓的内存地址即数组的下标索引. ...

  8. java 最少使用(lru)置换算法_「面试」LRU了解么?看看LinkedHashMap如何实现LRU算法...

    以下内容均是本人原创,希望你看完之后能有更多更深入的了解,欢迎关注➕ 问题:使用Java完成一个简单的LRU算法 什么是LRU算法 LRU(Least Recently Used),也就是最近最少使用 ...

  9. LinkedHashMap和HashMap的比较使用 详解

    由于现在项目中用到了LinkedHashMap,并不是太熟悉就到网上搜了一下. import java.util.HashMap;import java.util.Iterator;import ja ...

  10. 【Java源码分析】LinkedHashMap源码分析

    类的定义 public class LinkedHashMap<K, V> extends HashMap<K, V> {} 基于双向链表实现,属于Map的一类,其父类是Has ...

最新文章

  1. .net连接mysql数据_.net连接MYSQL数据库的方法及示例!
  2. QThread: Destroyed while thread is still running
  3. C++中为何构造函数不可是虚函数,而析构函数可以?
  4. 【Netty】NIO 网络编程 聊天室案例
  5. org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter错误解决
  6. 牛客 - 张老师的旅行(dp)
  7. [转]字符编码,ansi, unicode,utf-8, utf-16
  8. Serializing Lua objects into Lua Code
  9. 转: Spark 的核心概念 RDD
  10. oracle12 快照保存时间,【AWR】调整AWR数据采样时间间隔及历史快照保留时间
  11. Rails测试《十》不能错过的杂七杂八
  12. js动态创建元素和删除
  13. 阿里云数据库8月刊:国内首款Cloud Native自研数据库POLARDB精彩亮相VLDB!
  14. final类是否可以被代理_Java 动态代理机制分析及扩展,第 2 部分
  15. pycharm调试GreenOdoo
  16. 开启智慧新生活 新余市智慧城市建设全省率先
  17. Qt 网络编程制作一个客户端与服务器
  18. Lua xxtea 解密脚本(转,做备忘)
  19. 12306验证码破解思路分享
  20. (转)一位计算机牛人的心得,谈到计算机和数学,很实用

热门文章

  1. Django介绍工程搭建
  2. thrift数据类型
  3. python之 启动一个子进程并等待其结束
  4. 寒假挑战PythonTip(一人一python)总结——算法是程序的灵魂,程序员的心法
  5. POJ 2709 Painter
  6. 学习js,尝试写一个表单验证框架(1)-规划
  7. 阿里巴巴Java“代码反潜机”P3C喜提首届中国优秀开源项目二等奖!
  8. 『中级篇』k8s的NodePort类型Service以及Label的简单实用(68)
  9. [xsy2880]取石子游戏
  10. 程序员随笔:使用来自服务器的图像(有源码)