HashMap源码学习及7/8的对比

HashMap1.7

Jdk1.7的HashMap实质上是一个Entry数组,数组的每一个元素是一个单向链表,其数据结构以下:数组

HashMap的put方法:安全

  1. 判断map中的数组是不是空的,是则初始化数组。(可见HashMap在构造函数的时候其实啥都没干,真正初始化数组的时候是在put方法执行的)
  2. 判断key值是否为null,为null则将值放入在数组的第一个元素即table[0]
  3. 根据key计算出hash值
  4. 经过hash值从table数组找到对应的下表
  5. 取数组table对应下标的链表并遍历判断是否存在相同key值,存在则覆盖旧值并返回
  6. key值不存在则将Entry添加到链表中

仔细看看addEntry方法的实现,主要流程以下:数据结构

  1. 首先判断当前size是否已经达到了阈值且对应数组小标已经有值则须要扩容,扩容必定是数组大小的2倍,扩容后从新计算元素在新数组里的下表
  2. 在数组对应下表添加新的原色(新添加元素必定是添加都链表的表头,将next指向旧值)

HashMap的get方法函数

  1. 判断key值是否为空,为空直接从数据的第一个元素返回值
  2. 根据key计算出hash,根据hash找到对应数组下表,而后在根据hash从对应链表中取值便可

HashMap存在的非线程安全的问题:线程

  1. 扩容时候造成环形链表
  2. 添加数据时数据丢失

HashMap1.8

HashMap1.8相比1.7有比较大的改进,数据结构由1.7的数组+链表修改成数组+链表+红黑树,其中当链表的元素大于等于8的时候会转换成红黑树存储,另外就是扩容的时间点,1.7是先扩容再添加元素,1.8是先添加元素后再扩容。其数据结构由1.7的Entry数组变为Node数组,如: blog

put方法主要代码以下: get

get方法,相对比较简单:hash

  1. 经过key计算出hash值,而后找到对应数组的下表 2.判断对应下表的第一个值是否就是要找的对应key值,如果,直接返回,不然进行第3步
  2. 判断元素是链表仍是红黑树,而后相应的获取对应的值。

总结:table

  1. 两个版本采用的存储结构不一样,一个是数组+链表,一个是数组+链表+红黑树
  2. 扩容顺序不一样,1.7是先扩容再插入,1.8是先插入在扩容
  3. 1.8中链表转红黑树的条件是链表长度大于等于8 4.均不是线程安全
  4. 待补充
相关文章
相关标签/搜索