一、HashMap是什么?
HashMap 是一个散列(哈希)表,它存储的内容是键值对(key-value)映射。通过put()方法存储对象,get()方法获取对象。
HashMap 存放的元素是无序的,允许空键和空值(null),但是空键只能有一个,且放在第一位。
HashMap 的数据结构是由 “数组” + “链表” 来实现对数据的存储。
(1)数组:占用空间连续,寻址容易,查询速度快,但是增加和删除的效率非常低。
(2)链表:占用空间不连续,寻址困难,查询速度慢,但是增加和删除的效率非常高。(数组和链表的特点相反)
HashMap则结合了数组和链表的优点(即查询快,增删效率高)。
(HashMap是一种非常重要的数据结构,对于我们以后理解很多技术都非常有帮助,
比如:redis数据库的核心技术和HashMap差不多)
二、HashMap源码分析
注:本文使用jdk1.8分析HashMap源码
1.HashMap存储数据的过程:
理解了HashMap的基本结构之后,我们来继续深入学习HashMap如何存储数据。
首先,我们来查看HashMap的源码,如下图:
DEFAULT_INITIAL_CAPACITY: Node数组的默认长度(必须为2的整数幂)。
DEFAULT_LOAD_FACTOR:当Node数组实际装的数量达到了75%就会自动扩容。
Node数组:HashMap存放的元素都在Node数组中,每一个Node对象就是一个单向链表结构
(所以称HashMap的存储结构是“数组”+“链表”)
Node数组源码如下:
hash:每当HashMap存入一个元素,先根据key计算出一个hash值,得到一个存放位置。
存放位置=hash值%(Node数组长度-1)
那么不同的key计算出的hash值%(Node数组长度-1)会不会有一样的存放位置呢?答案是有。
next:Node数组中的单向链表,一旦发生冲突(一样的存放位置),那么冲突的元素则被存放在next中,以此类推。
上面说到,冲突的元素会放在链表(next)中,如果冲突的元素过多,那么查询的效率则会降低(链表的缺点),在jdk1.8中当链表存 储冲突的元素过多时,会采用红黑树来替代链表,从而解决查询效率低的问题。 而链表与红黑树之间的转换则由以下三个静态常量控制:
下面这段源码依旧是HashMap中的。
总结:
HashMap内部的数据结构:“数组”+“链表”。
HashMap存放元素的位置=key的hash值%(Node数组长度-1)。
HashMap处理冲突的元素是把冲突的元素存放在链表中,当冲突的数量>树化阈值则采用红黑树。
本文若有错误请留言指正,谢谢