源码分析(一) HashMap 源码分析|JDK8
HashMap是一个普遍应用于各大JAVA平台的最最最常用的数据结构。<K,V>的存储形式使HashMap备受广大java程序员的喜欢。JDK8中HashMap发生了很大的变化,例如:之前在JDK7中存在的indexFor方法被移除了,哈希碰撞后不再单纯的使用链表来解决,而是使用红黑树+单向链表来解决,之前Entry<K,V>也改换为Node<K,V>。对于红黑树我觉得这个是稍微有些复杂的,包括插入和删除,红黑树的旋转和5个基本原则我觉得这个是需要花时间来慢慢整理的。对数据结构的理解一定是关键中的关键。使用红黑二叉树的主要目的就是提升了检索的效率,O(N)->O(logN)
下面就我自己对HashMap的理解做一些总结。以下代码均来自jdk 1.8.0_73
- 基础部分
(1)组成结构:通俗的说,HashMap就是结合了哈希表和链表的一种实现,在JDK8之前,之所以采用链表的目的其实是在于方便解决哈希碰撞带来的影响,提高hash值相同的插入速度。但是当一个桶转化为一个链表的时候,效率还是会有所下降。在JDK8之后采用链表+红黑树的方式来解决哈希碰撞带来的问题HashMap底层维护一个数组,数组中的每一项都是一个Node<K,V>。
transient Node<K,V>[] table;//哈希表 3 transient Set<Map.Entry<K,V>> entrySet;//缓存
我们向 HashMap中所存储的数据实际上是存储在该数组当中,而HashMap中的key,value则是以Node<K,V>的形式存放在数组中。而这个Node应该放在数组的哪一个位置上(这个位置通常称为位桶或者hash桶,即hash值相同的Entry会放在同一位置,用链表相连或是红黑树),是通过key的hashCode来计算的。
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
Map的put方法:其实看起来还是有点麻烦的,源码上put方法上的注释提示了,如果key值相同则会替换。
/**
*
*
* 将给定的value映射到Map上,如果该map上存在相同的key值,则会替换为现有的值
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
putVal可以划分为这样的一个流程:
1)当前哈希表是否为空,如果为空就初始化一个
2)然后插入这个value,要是这个数组没有就插入,有的话就替代原先的value
3)要是hash碰撞了,看看当前位置是红黑树还是链表,然后插入。同样,要是发现key相同则进行覆盖。
4)要是当前链表长度超过阈值了(默认是8),就转红黑树
这里要有个约定:
1) 哈希表是一个大的数组,类型是Node<K,V>,规定这个是每个桶,
2)桶里装的是bin
3)size是node的数量,也就是你实际存放K,V的数量
4)capacity是桶的数量,没规定初始化容量时,一般默认是16个
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);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
源码分析(一) HashMap 源码分析|JDK8的更多相关文章
- JDK源码分析(三)——HashMap 下(基于JDK8)
目录 概述 内部字段及构造方法 哈希值与索引计算 存储元素 扩容 删除元素 查找元素 总结 概述 在上文我们基于JDK7分析了HashMap的实现源码,介绍了HashMap的加载因子loadFac ...
- [java源码解析]对HashMap源码的分析(二)
上文我们讲了HashMap那骚骚的逻辑结构,这一篇我们来吹吹它的实现思想,也就是算法层面.有兴趣看下或者回顾上一篇HashMap逻辑层面的,可以看下HashMap源码解析(一).使用了哈希表得“拉链法 ...
- 转:【Java集合源码剖析】HashMap源码剖析
转载请注明出处:http://blog.csdn.net/ns_code/article/details/36034955 您好,我正在参加CSDN博文大赛,如果您喜欢我的文章,希望您能帮我投一票 ...
- 源码解析之HashMap源码
关于HashMap的源码分析,网上已经有很多写的非常好的文章了,虽然多是基于java1.8版本以下的.Java1.8版本的HashMap源码做了些改进,理解起来更复杂点,但也不脱离其桶+链表或树的重心 ...
- 【Java集合源码剖析】HashMap源码剖析
转载出处:http://blog.csdn.net/ns_code/article/details/36034955 HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-va ...
- 【源码分析】HashMap源码再读-基于Java8
最近工作不是太忙,准备再读读一些源码,想来想去,还是先从JDK的源码读起吧,毕竟很久不去读了,很多东西都生疏了.当然,还是先从炙手可热的HashMap,每次读都会有一些收获.当然,JDK8对HashM ...
- [java源码解析]对HashMap源码的分析(一)
最近有空的时候研究了下HashMap的源码,平时我用HashMap主要拿来当业务数据整理后的容器,一直觉得它比较灵活和好用, 这样 的便利性跟它的组成结构有很大的关系. 直接开门见山,先简要说明一下H ...
- 【jdk源码3】HashMap源码学习
可以毫不夸张的说,HashMap是容器类中用的最频繁的一个,而Java也对它进行优化,在jdk1.7及以前,当将相同Hash值的对象以key的身份放到HashMap中,HashMap的性能将由O(1) ...
- HashMap源码阅读与解析
目录结构 导入语 HashMap构造方法 put()方法解析 addEntry()方法解析 get()方法解析 remove()解析 HashMap如何进行遍历 一.导入语 HashMap是我们最常见 ...
- Java 源码刨析 - HashMap 底层实现原理是什么?JDK8 做了哪些优化?
[基本结构] 在 JDK 1.7 中 HashMap 是以数组加链表的形式组成的: JDK 1.8 之后新增了红黑树的组成结构,当链表大于 8 并且容量大于 64 时,链表结构会转换成红黑树结构,它的 ...
随机推荐
- 找父节点和子节点个数(Poj1634)
题目链接:http://poj.org/problem?id=1634 思路:按照工资从小到大排好,找到最近的那个身高较高的人. 有一点要注意的是,这里有个根节点,大boss,他的id是0,因此,我这 ...
- Performing User-Managed Database-18.5、Restoring Control Files
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/offbeatmine/article/details/28429339 18.5.Restoring ...
- npm包发布过程
在上一章节中,我封装了一个基于react的树状组件,后来想把它发布到npm上,下面主要介绍一下发布过程中遇到的问题: 1.去注册npm账号,注册地址(https://www.npmjs.com), 再 ...
- python :编写装饰器
简单装饰器 def log_time(func): # 此函数的作用时接受被修饰的函数的引用test,然后被内部函数使用 def make_decorater(): print('现在开始装饰') f ...
- 2.Netty的粘包、拆包(一)
Netty粘包.拆包 1.什么是拆包.粘包 (1)拆包.粘包介绍 TCP是个"流"协议,所谓流,就是没有界限的一串数据.大家可以想想河里的流水,是连成一片的,其间并没有分界线.TC ...
- java循环删除List元素的方法总结
1.for循环 2.迭代器 3.过渡法 import java.util.*; /** * Created by HP on 2018/8/2. */ public class Test { publ ...
- Webpack4 学习笔记三 ES6+语法降级为ES5
前言 此内容是个人学习笔记,以便日后翻阅.非教程,如有错误还请指出 Webpack 将es6.es7语法降级为es5 需要通过 babel JavaScript编译器. 安装: npm i babel ...
- jQuery、Angluar、Avalon对比
最近在慕课网看一些关于avalon的视频,记录下一些笔记及代码实例以便日后自己复习可以用到,另外也可以给不想花时间看视频的小伙伴提供一丝丝帮助 这里主要是做一个简单的todolist 分别用三种不同的 ...
- Windows下MySQL数据库的安装与关闭开机自启动
我在学习java,安装数据库时找了很多教程,现在在这里总结一下我安装数据库的过程,我安装的是mysql-5.6.42-winx64版本的. 数据官方下载地址:https://dev.mysql.com ...
- Liunx 配置sshd服务
简介 SSH(Secure Shell)是一种能够提供安全远程登录会话的协议,也是目前远程管理Linux系统最首选的方式,因为传统的ftp或telnet服务是不安全的,它们会把帐号口令和数据资料等数据 ...