LinkedHashMap笔记
一、最基本元素存储单元
- /**
- * HashMap.Node subclass for normal LinkedHashMap entries.
- */
- 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);
- }
- }
还是原HashMap的,多了两个引用before,after,说明这是要用双向链表了
二、初始化 构造方法
- public LinkedHashMap() {
- super();
- accessOrder = false;
- }
- 多了 accessOrder = false;
- /**
- * The iteration ordering method for this linked hash map: <tt>true</tt>
- * for access-order, <tt>false</tt> for insertion-order.
- *
- * @serial
- */
- final boolean accessOrder;
- accessOrder表示迭代顺序,true表示访问顺序,false表示插入顺序。
三、put方法
put方法没有重写,因此和HashMap是一样的,但也有不同,不同在于LinkedHashMap实现了afterNodeAccess,afterNodeInsertion方法
看HashMap put源码
- final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
- boolean evict) {
- Node<K,V>[] tab; Node<K,V> p; int n, i;
- if ((tab = table) == null || (n = tab.length) == 0)
- n = (tab = resize()).length;
- if ((p = tab[i = (n - 1) & hash]) == null)
- tab[i] = newNode(hash, key, value, null);
- else {
- Node<K,V> e; K k;
- if (p.hash == hash &&
- ((k = p.key) == key || (key != null && key.equals(k))))
- e = p;
- else if (p instanceof TreeNode)
- e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
- else {
- for (int binCount = 0; ; ++binCount) {
- if ((e = p.next) == null) {
- p.next = newNode(hash, key, value, null);
- if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
- treeifyBin(tab, hash);
- break;
- }
- if (e.hash == hash &&
- ((k = e.key) == key || (key != null && key.equals(k))))
- break;
- p = e;
- }
- }
- if (e != null) { // existing mapping for key
- V oldValue = e.value;
- if (!onlyIfAbsent || oldValue == null)
- e.value = value;
- afterNodeAccess(e); //这个方法HashMap是空实现,这里是发生hash冲突后,找到有相同key对值进行处理时调用
- return oldValue;
- }
- }
- ++modCount;
- if (++size > threshold)
- resize();
- afterNodeInsertion(evict); //这个方法HashMap也是空实现,这里是完成新数据put后调用
- return null;
- }
- LinkedHashMap具体实现 :
- 1.void afterNodeAccess(Node<K,V> e) { // move node to last 注释就说明了是把该元素移到最后
- LinkedHashMap.Entry<K,V> last;
- if (accessOrder && (last = tail) != e) { //accessOrder用到了,默认false等于不运行,true时是按插入顺序
- LinkedHashMap.Entry<K,V> p =
- (LinkedHashMap.Entry<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;
- }
- }
- 以上代码看出在按插入顺序时,在有相同key时,对当前节点将其移到链表末尾
- 2.void afterNodeInsertion(boolean evict) { // possibly remove eldest
- LinkedHashMap.Entry<K,V> first;
- if (evict && (first = head) != null && removeEldestEntry(first)) {
- K key = first.key;
- removeNode(hash(key), key, null, false, true);
- }
- }
- removeEldestEntry 方法在jdk1.8中固定返回false,因此不用关注此方法
- 说明一下removeElestEntry用于定义删除最老元素的规则。一旦需要删除最老节点,那么将会调用removeNode删除节点。
举个例子,如果一个链表只能维持100个元素,那么当插入了第101个元素时,以如下方式重写removeEldestEntry的话,那么将会删除最老的一个元素
四、get方法(get进行了重写) ,在插入模式中,获取值后又一次进行把当前节点移到链表尾部操作
有点类似LRU(最少最近使用)算法~
- /*基于访问排序*/
- LinkedHashMap<String, String> linkedHashMap_accessOrder = new LinkedHashMap<>(10,0.75f,true);
- linkedHashMap_accessOrder.put("name1", "josan1");
- linkedHashMap_accessOrder.put("name2", "josan2");
- linkedHashMap_accessOrder.put("name3", "josan3");
- linkedHashMap_accessOrder.put("name4", "josan4");
- linkedHashMap_accessOrder.put("name5", "josan5");
- linkedHashMap_accessOrder.get("name5");
- linkedHashMap_accessOrder.get("name1");
- linkedHashMap_accessOrder.get("name2");
- linkedHashMap_accessOrder.get("name4");
- linkedHashMap_accessOrder.get("name3");
- //51243顺序
- for (Map.Entry<String, String> entry : linkedHashMap_accessOrder.entrySet()) {
- String key = entry.getKey();
- String value = entry.getValue();
- System.out.println("key:" + key + ",value:" + value);
- }
get方法: (accessOrder 为true表示按照访问排序),
- 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;
- }
将节点移动到最后:
- void afterNodeAccess(Node<K,V> e) { // move node to last
- LinkedHashMap.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;
- 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;
- }
- }
层层判断和更改引用之后,p已经独立出来了,就把p移到了map的末尾,实现了访问排序
五、总结
1. HashMap中TreeNode 即红黑树的节点类是继承LinkedHashMap.Entry
2. HashMap中没有使用双向链表,before, after没有使用,单纯的红黑树
3.LinkedHashMap是HashMap的子类,很多方法都是继承自父类,
LinkedHashMap中,存取等使用的也使用红黑树,但维护了before, after的链表属性,在存取时一样使用红黑树算法,
但keySet()、values()以及entrySet()等迭代时使用的是双向链表来进行的,这样的双向链表结构保证了插入顺序的有序。
4.总得来说,LinkedHashMap底层是数组加单项链表加双向链表。
5.数组加单向链表就是HashMap的结构,记录数据用,双向链表,存储插入顺序用。然后LInkedHashMap重写了两个方法,一个是添加entry,一个是创建entry,这两种时刻都要维护双向链表。
参考出处:https://www.cnblogs.com/zhaojj/p/7832680.html
LinkedHashMap笔记的更多相关文章
- jdk源码阅读笔记-LinkedHashMap
Map是Java collection framework 中重要的组成部分,特别是HashMap是在我们在日常的开发的过程中使用的最多的一个集合.但是遗憾的是,存放在HashMap中元素都是无序的, ...
- java集合类学习笔记之LinkedHashMap
1.简述 LinkedHashMap是HashMap的子类,他们最大的不同是,HashMap内部维护的是一个单向的链表数组,而LinkedHashMap内部维护的是一个双向的链表数组.HashMap是 ...
- JDK源码学习笔记——LinkedHashMap
HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序. LinkedHashMap保证了元素迭代的顺序.该迭代顺序可以是插入顺序或者是访问顺序.通过维护一个 ...
- Java TreeMap 和 LinkedHashMap【笔记】
Java TreeMap 和 LinkedHashMap[笔记] TreeMap TreeMap基本结构 TreeMap 底层的数据结构就是红黑树,和 HashMap 的红黑树结构一样 与HashMa ...
- LinkedHashMap源码阅读笔记(基于jdk1.8)
LinkedHashMap是HashMap的子类,很多地方都是直接引用HashMap中的方法,所以需要注意的地方并不多.关键的点就是几个重写的方法: 1.Entry是继承与Node类,也就是Linke ...
- HashMap LinkedHashMap源码分析笔记
MapClassDiagram
- 【Java学习笔记】HashMap子接口---LinkedHashMap
特点: 存入元素的顺序 与 取出元素的顺序相同(与LinkedHashSet类似) import java.util.HashMap; import java.util.Iterator; i ...
- Java基础知识强化之集合框架笔记58:Map集合之LinkedHashMap类的概述
1. LinkedHashMap类的概述 LinkedHashMap:Map接口的哈希表(保证唯一性) 和 链接(保证有序性)列表实现,具有可预知的迭代顺序. 2. 代码示例: package cn. ...
- Java笔记(八)TreeMap & TreeSet & LinkedHashMap
TreeMap & TreeSet & LinkedHashMap 一.TreeMap HashMap缺陷:键值对之间没有特定的顺序.在TreeMap中, 键值对之间按键有序,Tree ...
随机推荐
- ionic-Javascript:ionic 上拉菜单(ActionSheet)
ylbtech-ionic-Javascript:ionic 上拉菜单(ActionSheet) 1.返回顶部 1. ionic 上拉菜单(ActionSheet) 上拉菜单(ActionSheet) ...
- 20140319 const sizeof define 编译时分配内存
1.面试宝典预处理,const,sizeof Define作用定义函数: //用一个宏定义FIND求一个结构体struc里某个变量相对于struc的偏移量,如FIND(student,a)//等于0 ...
- 【6折抢】戴尔i7新品Latitude高性能商用本
致敬拼搏成长中的企业 戴尔5月有钜惠! 买1赠1送同款,单台价格2500元 这波来自戴尔官网的致敬很走心 满足初级办公和高性能运算多重需求 限时折扣火热开抢! 新品 latitude 6折抢! 戴尔 ...
- Git仓库操作命令
创建仓库 git init 在当前目录执行,会生成.git目录文件,这个和SVN一致. 提交到仓库 git commit -m "first commit" -m:表示提交描述,必 ...
- java-day13
异常 指的是程序在执行过程中,出现的非正常情况,最终会导致JVM的非正常停止 异常分类:编译异常,运行期异常 异常的产生过程分析 throw关键字:指方法中抛出指定异常 使用格式:throw new ...
- 调用第三方jar包_md5加密
vars.put是转换成jmeter格式
- 免费的高分辨率图库——re:splashed 可用做网页背景、设计或桌面壁纸
想找高清图片用作网站背景.设计或桌面壁纸?可以去re:splashed看看.re:splashed 是一个提供免费高分辨率HD图片的网站,有多种分类标签,查找很方便,无需注册和登陆便可下载. 网站名称 ...
- js 实现多选
效果: html: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> < ...
- .net中的泛型全面解析
从2.0起我们一直就在谈论泛型,那么什么是泛型,泛型有什么好处,与泛型相关的概念又该怎么使用,比如泛型方法,泛型委托.这一篇我会全面的介绍泛型. 那么首先我们必须搞清楚什么是泛型,泛型其实也是一种类型 ...
- python 取出aws中ip有,zabbix中没有的ip
#!/usr/bin/env python3# coding=utf-8import requestsimport jsonimport boto3 headers = {'Content-Type' ...