源码分析(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倍 建议指定容量大小,减少扩容带来的性能消耗 ...
随机推荐
- flask之request
from flask import Flask, render_template, redirect, jsonify, send_file, request, session app = Flask ...
- Django操作session实例
session项目文件: templates模板: login.html {% load static %} <!DOCTYPE html> <html lang="en& ...
- npm run build 时 报 __webpack_public_path__ = window.webpackPublicPath; 中的windows未定义
原本 webpack.js在webpack.config.babel.js同目录下,在app.jsx中引用,用mac打包没问题,但是window就报window未定义,改到src和app.jsx同目录 ...
- Poj 3013基础最短路
Description Christmas is coming to KCM city. Suby the loyal civilian in KCM city is preparing a big ...
- CF1013D Chemical table
题目链接:http://codeforces.com/contest/1013/problem/D 题目大意: 给出一个 \(n \times m\) 的表格,表格上有一些初始点.若有这样的三个点:\ ...
- 【python爬虫】解决歌荒,下歌利器
python下载图片,mp3,想必很多人都早已耳闻,今天给大家来点不一样的, 让你下载高逼格高品质,带进度条,实时显示下载速度 详见源码:https://www.kesci.com/home/proj ...
- WordPress批量更换域名
UPDATE wp_options SET option_value = replace( option_value, 'http://www.old.com', 'http://www.new.co ...
- [JavaWeb基础] 023.线程安全(二)
上一篇我们讲解了线程安全的问题,那么要解决线程安全的问题,我们就必须用到线程同步,保证线程之间不互相影响而产生脏数据,下面我们来讲讲具体的实现吧. 首先我们看下例子,我们有个Outputter类,用于 ...
- [C#反编译教程]001.Reflector.NET反编译工具 v8.5绿色版+注册机+注册教程
截图 下载地址 Reflector.NET反编译工具 v8.5绿色版+注册机 下载地址:http://pan.baidu.com/s/1mgN1Cpi 密码:mx19 简介 .NET Reflecto ...
- [安卓基础] 008.Android中的显示单位
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...