HashMap
一、前言
二、JDK1.7 HashMap的实现
三、JDK1.8 HashMap的实现
四、HashMap的存储过程
五、HashMap的扩容
六、哈希碰撞
七、HashMap为什么使用链表?
八、HashMap为什么使用红黑树?
一、前言
为什么需要了解HashMap底层原理呢?
因为面试的时候面试官一般都会问
HashMap在Java开发过程中是一个十分常用的集合类,它是一个以键值对形式存在的集合类
二、JDK1.7 HashMap的实现
JDK1.7 HashMap的实现是 通过数组+链表的形式
三、JDK1.8 HashMap的实现
JDK1.8 HashMap的实现是 通过数组+链表+红黑树的形式
四、HashMap的存储过程
假设有一段数据 key="柳岩" value="18"
假设向哈希表中存储 "柳岩" "18"
,根据"柳岩"
调用String类中重写之后的hashcode方法计算出值,然后结合数组长度采用某种算法计算出向Node数组中存储数据的空间的索引值.
如果计算出的索引空间没有数据,则直接将"柳岩" "18"
存储到数组对应的索引中.举例:通过计算得出柳岩
的的索引值是3 那么就存放到数组下标3中
假设向哈希表中在存放一组数据"刘德华" "40"
假设刘德华
计算出的hashcode方法结合数组长度计算出的索引也是3 ,那么此时数组空间不为null的话,底层就会比较柳岩和刘德华的hash是否一致,如果不一致,则在此空间划出一个链表节点来存储键值对数据"刘德华" "40"
也就是通过(拉链法)来解决这个问题
五、HashMap的扩容
当链表大于8 数组小于64 扩容是原来的两倍 并将原有的数据复制过来 举例 默认数组长度16 乘以加载因子0.75=12 当数组长度大于12扩容两倍
六、哈希碰撞
假设向哈希表存放数据 "柳岩" "20"
那么通过hashcode结合数组长度计算出的柳岩的索引肯定也是3,此时比较后储存的数据柳岩
和已经存在的数据的hash值是否相等,如果值相等,此时发生hash碰撞.
那么底层会调用柳岩所属类String中的equals方法比较两个内容是否相等:
相等:则将后添加的数据的value覆盖之前的value
不相等:那么继续向下和其他数据的key进行比较,如果都不相等,则划出一个节点储存数据
七、HashMap为什么使用链表?
链表的实现是为了解决hash冲突:
那么hash冲突是什么?
首先我们要了解hashmap是怎么存值的,hashmap 的key存放地址是通过hashcode方法计算出值,通过值找到相应位置存放,那么就有可能在hashcode方法计算值的时候出现,相同的值,这个时候就会出现hash冲突了,然而链表很好的解决的hash冲突,在相同的地址上开辟一个链表,存放通过hashcode计算出新的相同key值的数据
八、HashMap为什么使用红黑树?
黑树的实现是为了解决链表过长,出现的效率变低
怎么实现红黑树?
当链表的阈值达到8 并且数值大于64 那么链表自动转换成红黑树
为什么要达到阈值8 或者数组64才实现红黑树?
因为数组过小,如果提前实现红黑树反而效率会减低,因为红黑树需要进行左旋,右旋,变色这些操作来保持平衡.数组小于64时不实现红黑树,搜索时间会快一点
但是如果数组大于64 阈值大于8 实现红黑树,效率则会快一点