LinkedHashMap 原理

基于jdk1.8

HashMap原理:http://www.cnblogs.com/zhaojj/p/7805376.html

LinkedHashMap 继承HashMap
没有重写put resize等方法 因此基本数据结构是相同的数组、链表、红黑树

说说不同:
一、最基本元素存储单元

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进行了重写

 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;
} 唯一需要关注的就是在插入模式中,获取值后又一次进行把当前节点移到链表尾部操作

五、其它
1.需要注意HashMap中TreeNode 即红黑树的节点类是继承LinkedHashMap.Entry
在HashMap中没有使用双向链表,before, after没有使用,单纯的红黑树
在LinkedHashMap中,存取等使用的也使用红黑树,但维护了before, after的链表属性,在存取时一样使用红黑树算法,但keySet()、values()以及entrySet()等迭代时使用的是双向链表来进行的

即存取是一样 但遍历不同,LinkedHashMap把所有插入的元素又全部重新维护了一个双向链表遍历时用的是这个链表,它的有序就是靠这个链表了玩的。简单理解就是和hashmap都一样,只是加了个双向链表的结构用于遍历体现有序性。

2.LinkedHashMap只有在使用三个参数的构造方法并制定accessOrder为true时,才有顺序,不指定那么和HashMap基本没什么大的区别
所谓的顺序是指插入顺序,而不是通常意义上的大小顺序

java8 LinkedHashMap 原理的更多相关文章

  1. LinkedHashMap原理

    作者:艺旭家 链接:https://www.jianshu.com/p/8f4f58b4b8ab 总结 LinkedHashMap是继承于HashMap,是基于HashMap和双向链表来实现的. Ha ...

  2. 图解LinkedHashMap原理

    1 前言 LinkedHashMap继承于HashMap,如果对HashMap原理还不清楚的同学,请先看上一篇:图解HashMap原理 2 LinkedHashMap使用与实现 先来一张LinkedH ...

  3. JDK source 之 LinkedHashMap原理浅谈

    注:本文参考JDK1.7.0_45源码. LinkedHashMap是基于HashMap实现的数据结构,与HashMap主要的不同为每个Entry是使用双向链表实现的,并且提供了根据访问顺序进行排序的 ...

  4. java8 HashTable 原理

    HashTable原理 Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现.Hashtable中的方法是同步的,而HashMap方法(在 ...

  5. Java基础之LinkedHashMap原理分析

    知识准备HashMap 我们平时用LinkedHashMap的时候,都会写下面这段 LinkedHashMap<String, Object> map = new LinkedHashMa ...

  6. LinkedHashMap原理以及场景

    http://www.cnblogs.com/xiaoxi/p/6170590.html

  7. Java集合之LinkedHashMap

    一.初识LinkedHashMap 上篇文章讲了HashMap.HashMap是一种非常常见.非常有用的集合,但在多线程情况下使用不当会有线程安全问题. 大多数情况下,只要不涉及线程安全问题,Map基 ...

  8. 图解集合6:LinkedHashMap

    初识LinkedHashMap 上两篇文章讲了HashMap和HashMap在多线程下引发的问题,说明了,HashMap是一种非常常见.非常有用的集合,并且在多线程情况下使用不当会有线程安全问题. 大 ...

  9. java8Stream原理深度解析

    Java8 Stream原理深度解析 Author:Dorae Date:2017年11月2日19:10:39 转载请注明出处 上一篇文章中简要介绍了Java8的函数式编程,而在Java8中另外一个比 ...

随机推荐

  1. spring cloud 2.x版本 Gateway路由网关教程

    前言 本文采用Spring cloud本文为2.1.8RELEASE,version=Greenwich.SR3 本文基于前两篇文章eureka-server.eureka-client.eureka ...

  2. Dubbo从入门到实战:实战篇

    一.加入 zookeeper 作为注册中心 在前面的案例中,我们没有使用任何的注册中心,而是用一种直连的方式进行的.但是,实际上很多时候,我们都是使用 dubbo + zookeeper 的方式,使用 ...

  3. CRF keras代码实现

    这份代码来自于苏剑林 # -*- coding:utf-8 -*- from keras.layers import Layer import keras.backend as K class CRF ...

  4. oracle trunc 日期 数字 的使用例子

    /**************日期********************/1.select trunc(sysdate) from dual --2013-01-06 今天的日期为2013-01-0 ...

  5. .net core程序强制以管理员权限启动

    当我们编写windows程序的时候,很多时候需要程序默认以管理员权限运行,以前在.net 程序中直接新建一个app.manifest,设置requestedExecutionLevel 节点即可 &l ...

  6. Android中几种常用的定时器和延时方法

    通过实际项目的练习,掌握了几种android基本定时器和延时的用法,这里我想总结一下作为自己的收获,下面列出的是比较简洁的模式,方便简单地在程序中直接调用. 一.三种常用的定时器 1.Handler类 ...

  7. DataGridView中获取与设置当前选中行以及SelectedRows和CurrentRow注意区分

    场景 DataGridView怎样实现添加.删除.上移.下移一行: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10281414 ...

  8. VUE基础实用技巧

    Vue以前听说过,有了解过一点.当时还在热衷于原生JavaScript去写一些方法的封装,不是为啥,就感觉这样很帅,后面多多少少接触了一些JQuery的用法,到现在为止,JavaScript原生封装的 ...

  9. CMD查看redis

    进入redis安装目录执行 redis-cli.exe -h 127.0.0.1 -p 6379

  10. uni-app自定义导航栏按钮|uniapp仿微信顶部导航条

    最近一直在学习uni-app开发,由于uniapp是基于vue.js技术开发的,只要你熟悉vue,基本上很快就能上手了. 在开发中发现uni-app原生导航栏也能实现一些顶部自定义按钮+搜索框,只需在 ...