源码分析(2)-LinkedHashMap(JDK1.8)
1、概述
LinkedHashMap继承自HashMap;在HashMap基础上,通过维护一条双向链表,解决了HashMap键值对遍历顺序和插入顺序一致的问题。
想了解LinkedHashMap源码,首先需要了解HashMap源码。
2、原理
3、源码分析
结合我的《源码分析(1)-HashMap(JDK1.8)》文章 https://www.cnblogs.com/wangymd/p/11750194.html。
3.1、成员属性
//双向联调头
transient LinkedHashMap.Entry<K,V> head;
//双向联调尾
transient LinkedHashMap.Entry<K,V> tail;
//
final boolean accessOrder;
//数据结构
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);
}
}
3.2、插入操作
插入操作复用父类方法putVal方法,重写创建节点方法、增加维护双向联调的方法。
//重写父类HashMap的newNode方法,创建hash桶节点
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;
}
//重写父类HashMap的newTreeNode方法,创建红黑树节点
TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
TreeNode<K,V> p = new TreeNode<K,V>(hash, key, value, next);
linkNodeLast(p);
return p;
}
//新增加点添加到双向联调尾部
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
LinkedHashMap.Entry<K,V> last = tail;
tail = p;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}
//重写父类HashMap的replacementNode方法,红黑树节点转换为链表节点
Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
LinkedHashMap.Entry<K,V> t =
new LinkedHashMap.Entry<K,V>(q.hash, q.key, q.value, next);
transferLinks(q, t);
return t;
}
//重写父类HashMap的replacementTreeNode方法,链表节点转换为红黑树节点
TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
TreeNode<K,V> t = new TreeNode<K,V>(q.hash, q.key, q.value, next);
transferLinks(q, t);
return t;
}
3.3、删除操作
删除操作复用父类方法removeNode方法,重写afterNodeRemoval维护双向链表数据结构。
//重写父类HashMap的afterNodeRemoval方法,维护双向链表数据结构
void afterNodeRemoval(Node<K,V> e) { // unlink
LinkedHashMap.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;
else
b.after = a;
if (a == null)
tail = b;
else
a.before = b;
}
3.4、查询操作
查询操作重写父类方法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;
}
//
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) {//定位hash桶位置
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))//查询结果头结点
return first;
if ((e = first.next) != null) {//查询结果不是头结点
if (first instanceof TreeNode)//节点类型红黑树
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {//节点类型链表
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
参考文章:
https://www.imooc.com/article/22931
源码分析(2)-LinkedHashMap(JDK1.8)的更多相关文章
- 【集合框架】JDK1.8源码分析之LinkedHashMap(二)
一.前言 前面我们已经分析了HashMap的源码,已经知道了HashMap可以用在哪种场合,如果这样一种情形,我们需要按照元素插入的顺序来访问元素,此时,LinkedHashMap就派上用场了,它保存 ...
- java基础系列之ConcurrentHashMap源码分析(基于jdk1.8)
1.前提 在阅读这篇博客之前,希望你对HashMap已经是有所理解的,否则可以参考这篇博客: jdk1.8源码分析-hashMap:另外你对java的cas操作也是有一定了解的,因为在这个类中大量使用 ...
- 源码分析系列1:HashMap源码分析(基于JDK1.8)
1.HashMap的底层实现图示 如上图所示: HashMap底层是由 数组+(链表)+(红黑树) 组成,每个存储在HashMap中的键值对都存放在一个Node节点之中,其中包含了Key-Value ...
- 源码分析--HashMap(JDK1.8)
在JDK1.8中对HashMap的底层实现做了修改.本篇对HashMap源码从核心成员变量到常用方法进行分析. HashMap数据结构如下: 先看成员变量: 1.底层存放数据的是Node<K,V ...
- Java 容器源码分析之 LinkedHashMap
同 HashMap 一样,LinkedHashMap 也是对 Map 接口的一种基于链表和哈希表的实现.实际上, LinkedHashMap 是 HashMap 的子类,其扩展了 HashMap 增加 ...
- JDK源码分析(四)——LinkedHashMap
目录 LinkedHashMap概述 内部字段及构造方法 存储元素 取出元素 删除元素 迭代器 利用LinkedHashMap简单实现LRU算法 总结 LinkedHashMap概述 JDK对Li ...
- HashMap源码分析(基于JDK1.6)
在Java集合类中最常用的除了ArrayList外,就是HashMap了.本文尽自己所能,尽量详细的解释HashMap的源码.一山还有一山高,有不足之处请之处,定感谢指定并及时修正. 在看Hash ...
- 源码分析--HashSet(JDK1.8)
HashSet为无序不可重复集合.底层几乎全部借助HashMap实现,比较简单.本篇简要分析一下HashSet源码. 首先是成员变量: 1.真正保存数据的HashMap实例 private trans ...
- 源码分析--ArrayList(JDK1.8)
ArrayList是开发常用的有序集合,底层为动态数组实现.可以插入null,并允许重复. 下面是源码中一些比较重要属性: 1.ArrayList默认大小10. /** * Default initi ...
- ArrayList源码分析笔记(jdk1.8)
1.特点: ArrayList 是一个动态数组,它是线程不安全的,允许元素为null 可重复,插入有序 读写快,增删慢 扩容:默认容量 10,默认扩容1.5倍 建议指定容量大小,减少扩容带来的性能消耗 ...
随机推荐
- Angular知识点复习
Angular第三方UI组件库(github搜“awesome angular ")-----lonic 概述:是一个第三方的适用于移动端App的UI组件库,可以与Angular/React ...
- 【Redis】Hash常见应用场景 - 电商购物车
电商购物车 以用户id为key 商品id为field 商品数量为value 购物车操作 [key(用户id),field(商品id),value(数量)] 添加商品 -> hset cart: ...
- [原创]RTX使用printf输出后进入hardfault中断的处理方法 - 讨论
今天我用到RTX里面使用printf ,发现程序死掉了 我发现很多人遇到了这样的问题 找了网上很多的文章,说是这个是RTX的一个先天不足的问题 我发现了正点原子的 原子哥的解决方案,如下所示: --- ...
- Redis数据迁移同步工具(redis-shake)
前言 最近线上一台自建redis服务的服务器频繁报警,内存使用率有点高,这是一台配置比较简陋(2C8G)的机子了,近期也打算准备抛弃它了.抛弃之前需对原先的数据进行迁移,全量数据,增量数据都需要考虑, ...
- 阿里P9精心编写高并发设计手册,来看大厂是如何进行系统设计
在看这篇文章的应该都是IT圈的朋友吧,不知道你们有没有考虑过这样几件事: 淘宝双11的剁手狂欢为什么天猫没崩掉? 为什么滴滴打车高峰如何滴滴依旧可以平稳运行? 为什么疫情期间,钉钉能支撑那么多人同时上 ...
- 项目readme文件目录生成工具 treer
生成目录的工具呢有tree和treer,但是tree不知道怎么忽略node_modules文件夹, 而treer就简单了,下面就是基本的命令了 其中-i是指忽略xxx, -e是指导出 安装 npm i ...
- 前端基础进阶(十五):详解 ES6 Modules
对于新人朋友来说,想要自己去搞定一个ES6开发环境并不是一件容易的事情,因为构建工具的学习本身又是一个非常大的方向,我们需要花费不少的时间才能掌握它. 好在慢慢的开始有大神提供了一些非常简单易懂,学习 ...
- 浅谈进程&线程
学习过操作系统(下面简称OS)的都清楚,计算机计算的核心是CPU,操作系统是计算机资源的管理者 同事也是软硬件之间的接口.为了实现程序的并发,而引入了进程的概念.在传统OS中,进程是个很重要的概念,它 ...
- 基于 kubeadm 搭建高可用的kubernetes 1.18.2 (k8s)集群 三 集群可用性测试
1. 创建nginx ds # 写入配置 $ cat > nginx-ds.yml <<EOF apiVersion: v1 kind: Service metadata: name ...
- python之robotframework+pycharm测试框架
一.robotframework简介 Robot Framework是一款python编写的功能自动化测试框架.具备良好的可扩展性,支持关键字驱动,可以同时测试多种类型的客户端或者接口,可以进行分布式 ...