LinkedHashMap
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相关推荐
- LinkedHashMap and LinkedHashSet
LinkedHashMap实现了Map接口,是HashMap的直接子类,它同时满足HashMap和linked list的某些特性.可将LinkedHashMap看作采用linked list增强的H ...
- LInkedHashMap实现最近被使用(LRU)缓存
在最近的面试中,我曾被多次问到,怎么实现一个最近最少使用(LRU)的缓存.缓存可以通过哈希表来实现,然而为这个缓存增加大小限制会变成另一个有意思的问题.现在我们看一下怎么实现. 最近最少使用缓存的回收 ...
- 彻底理解HashMap及LinkedHashMap
欢迎关注方志朋的博客,回复"666"获面试宝典 来源:https://blog.csdn.net/fuzhongmin05/article/details/104355841 Ha ...
- HashMap和LinkedHashMap的区别
转自:https://www.cnblogs.com/yuexzh/p/7486264.html HashMap,LinkedHashMap,TreeMap都属于Map Map 主要用于存储键(key ...
- linkedhashmap 顺序_有关于LinkedHashMap一份简单理解
/ 今日科技快讯 / 近日,台湾地区媒体<经济日报>转引<日经亚洲评论>报道称,自去年起,已有100多位原台积电工程师和经理人员被挖角到中国大陆,从事芯片研发制造项目.对此台积 ...
- HashTable, HashMap, LinkedHashMap, ConcurrentHashMap
HashTable: 不允许null的key或value, 线程安全 HashMap: 允许一个null的key, 无限的null value, 非线程安全 LinkedHashMap: HashMa ...
- HashMap,LinkedHashMap,TreeMap的有序性
HashMap 是将 Key 做 Hash 算法,然后将 Hash 值映射到内存地址,直接取得 Key 所对应的数据.在 HashMap 中,底层数据结构使用的是数组,所谓的内存地址即数组的下标索引. ...
- java 最少使用(lru)置换算法_「面试」LRU了解么?看看LinkedHashMap如何实现LRU算法...
以下内容均是本人原创,希望你看完之后能有更多更深入的了解,欢迎关注➕ 问题:使用Java完成一个简单的LRU算法 什么是LRU算法 LRU(Least Recently Used),也就是最近最少使用 ...
- LinkedHashMap和HashMap的比较使用 详解
由于现在项目中用到了LinkedHashMap,并不是太熟悉就到网上搜了一下. import java.util.HashMap;import java.util.Iterator;import ja ...
- 【Java源码分析】LinkedHashMap源码分析
类的定义 public class LinkedHashMap<K, V> extends HashMap<K, V> {} 基于双向链表实现,属于Map的一类,其父类是Has ...
最新文章
- .net连接mysql数据_.net连接MYSQL数据库的方法及示例!
- QThread: Destroyed while thread is still running
- C++中为何构造函数不可是虚函数,而析构函数可以?
- 【Netty】NIO 网络编程 聊天室案例
- org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter错误解决
- 牛客 - 张老师的旅行(dp)
- [转]字符编码,ansi, unicode,utf-8, utf-16
- Serializing Lua objects into Lua Code
- 转: Spark 的核心概念 RDD
- oracle12 快照保存时间,【AWR】调整AWR数据采样时间间隔及历史快照保留时间
- Rails测试《十》不能错过的杂七杂八
- js动态创建元素和删除
- 阿里云数据库8月刊:国内首款Cloud Native自研数据库POLARDB精彩亮相VLDB!
- final类是否可以被代理_Java 动态代理机制分析及扩展,第 2 部分
- pycharm调试GreenOdoo
- 开启智慧新生活 新余市智慧城市建设全省率先
- Qt 网络编程制作一个客户端与服务器
- Lua xxtea 解密脚本(转,做备忘)
- 12306验证码破解思路分享
- (转)一位计算机牛人的心得,谈到计算机和数学,很实用
热门文章
- Django介绍工程搭建
- thrift数据类型
- python之 启动一个子进程并等待其结束
- 寒假挑战PythonTip(一人一python)总结——算法是程序的灵魂,程序员的心法
- POJ 2709 Painter
- 学习js,尝试写一个表单验证框架(1)-规划
- 阿里巴巴Java“代码反潜机”P3C喜提首届中国优秀开源项目二等奖!
- 『中级篇』k8s的NodePort类型Service以及Label的简单实用(68)
- [xsy2880]取石子游戏
- 程序员随笔:使用来自服务器的图像(有源码)