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. 基础部分

  (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的更多相关文章

  1. JDK源码分析(三)——HashMap 下(基于JDK8)

    目录 概述 内部字段及构造方法 哈希值与索引计算 存储元素 扩容 删除元素 查找元素 总结 概述   在上文我们基于JDK7分析了HashMap的实现源码,介绍了HashMap的加载因子loadFac ...

  2. [java源码解析]对HashMap源码的分析(二)

    上文我们讲了HashMap那骚骚的逻辑结构,这一篇我们来吹吹它的实现思想,也就是算法层面.有兴趣看下或者回顾上一篇HashMap逻辑层面的,可以看下HashMap源码解析(一).使用了哈希表得“拉链法 ...

  3. 转:【Java集合源码剖析】HashMap源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/36034955   您好,我正在参加CSDN博文大赛,如果您喜欢我的文章,希望您能帮我投一票 ...

  4. 源码解析之HashMap源码

    关于HashMap的源码分析,网上已经有很多写的非常好的文章了,虽然多是基于java1.8版本以下的.Java1.8版本的HashMap源码做了些改进,理解起来更复杂点,但也不脱离其桶+链表或树的重心 ...

  5. 【Java集合源码剖析】HashMap源码剖析

    转载出处:http://blog.csdn.net/ns_code/article/details/36034955 HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-va ...

  6. 【源码分析】HashMap源码再读-基于Java8

    最近工作不是太忙,准备再读读一些源码,想来想去,还是先从JDK的源码读起吧,毕竟很久不去读了,很多东西都生疏了.当然,还是先从炙手可热的HashMap,每次读都会有一些收获.当然,JDK8对HashM ...

  7. [java源码解析]对HashMap源码的分析(一)

    最近有空的时候研究了下HashMap的源码,平时我用HashMap主要拿来当业务数据整理后的容器,一直觉得它比较灵活和好用, 这样 的便利性跟它的组成结构有很大的关系. 直接开门见山,先简要说明一下H ...

  8. 【jdk源码3】HashMap源码学习

    可以毫不夸张的说,HashMap是容器类中用的最频繁的一个,而Java也对它进行优化,在jdk1.7及以前,当将相同Hash值的对象以key的身份放到HashMap中,HashMap的性能将由O(1) ...

  9. HashMap源码阅读与解析

    目录结构 导入语 HashMap构造方法 put()方法解析 addEntry()方法解析 get()方法解析 remove()解析 HashMap如何进行遍历 一.导入语 HashMap是我们最常见 ...

  10. Java 源码刨析 - HashMap 底层实现原理是什么?JDK8 做了哪些优化?

    [基本结构] 在 JDK 1.7 中 HashMap 是以数组加链表的形式组成的: JDK 1.8 之后新增了红黑树的组成结构,当链表大于 8 并且容量大于 64 时,链表结构会转换成红黑树结构,它的 ...

随机推荐

  1. 最小堆的维护,POJ(2051)

    题目链接:http://poj.org/problem?id=2051 ///维持最小堆(优先队列)POJ2051 #include <iostream> #include <str ...

  2. 【转】jpg png区别和使用

    为什么想整理这方面的类容,我觉得就像油画家要了解他的颜料和画布.雕塑家要了解他的石材一样,作为网页设计师也应该对图片格式的特性有一定了解,这样才能更好的表达你的创意和想法. 除此之外,我们在平时工作中 ...

  3. R 语言学习日志 1

      1. CSV文件的的读取与写出 2. 数据集筛选 3. 简单随机抽样 sample函数   正文: 1. CSV文件的的读取与写出 文件读取: df2 <- read.table(" ...

  4. VMWare关闭beep声

    在虚拟机文件夹下找到 .vmx 文件,在文件末尾添加 mks.noBeep = "TRUE" ,重启虚拟机即可.

  5. django中介模型,CBV模型,及logging日志配制

    1.中介模型 中介模型,这个是在我们创建表格时,多对多添加的时候应用到的,通过制定ManyToManyField字段中的through参数来定义,为两者的关系新建一个中介class 为什么会产生这个中 ...

  6. 3.初识Cron表达式

    Cron: 计划任务,是任务在约定的时间执行已经计划好的工作,这是表面的意思.在Linux中,我们经常用到 cron 服务器来完成这项工作.cron服务器可以根据配置文件约定的时间来执行特定的作务. ...

  7. cmd文件内容添加到文件内容命令

    今天需要因为有点SQL文件需要添加修改,但是感觉是做运维工作得当然不能一个一个来了.搞了半天bat才找到这个命令(真是一个不合格的运维) 例如:a.txt 内容添加到 b.txt (不是覆盖,而是在 ...

  8. C编程经验总结4

    {}体里的语句不管在一行还是在多行,之间都是要有: for与for之间可以是独立的,也可以是相互嵌套的 For( ; i<5; )=for( ;i<=4;  ) 一般都是在循环里面进行判断 ...

  9. 写给iOS小白的MVVM教程(一): 从MVC到MVVM之一个典型的MVC应用场景

    前言 本着实践为主的原则,此系列文章不做过多的概念性的阐述和讨论;更多的代码和篇幅用来展示MVC和MVVC下的基础代码结构与具体实现,来展示各自优劣.这篇文章,更多的在于发掘MVC与MVVC的共性,以 ...

  10. 实战 Lucene2.0

    Lucene 简介 Lucene 是一个基于 Java 的全文信息检索工具包,它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能.Lucene 目前是 Apache Jakarta 家 ...