以下是JDK1.8之前版本的源码简介
一、什么是HashMap
Hash:散列将一个任意的长度通过某种(hash函数算法)算法转换成一个固定值。
Map:存储的集合
HashMap是数组+链表的数据结构
总结:通过hash出来的值,然后通过这个值定位到这个map,然后把这个value存储到这个map中。
此类不保证映射顺序,也不保证映射顺序恒久不变。
数组长度默认16
面试:HashMap是什么时候做扩容?
put的时候数据组长度达到的0.75(3/4)的时候扩容,扩容当前长度的2倍
put的Key,hash冲突时,不会覆盖老的值,返回老的值,否则返回空。
hashMap table :数组+链表 数据结构
二、源码分析
1、初始化参数介绍
transient Entry []table; //存储元素的实体数组
transient int size; //存储的元素个数
int threshold; //临界值,当实际大小超过临界值时,会进行扩容threshold=加载因子*数组长度
final float loadFactor; //加载因子,默认0.75,也就是数组的3/4
2、put方法分析
当程序向hashmap put一个key-value时,首先根据key的hashcode()返回值决定Entry存储的位置,如果二个hashcode发生冲突时,那么它们储存在数组的位置相同。如果key通过equals方法对比为true,新的Entry的value覆盖原有的value;如果key通过equals方法对比为false,新Entry放入旧的Entry位置,旧Entry设置为新Entry的next,也就是新entry链表的下一个节点。
如果size大于临界值(加载因子*数组长度)就以2的倍数扩容。
resize()方法,新建一个entry数组,将旧的全部元素添加到新的entry数组,需要重新计算元素在新的数组中的索引位置。
当hashMap中的元素越来越多的时候,hash冲突的几率也越来越高,因为数组的长度是固定的。所以为了提高查询效率,就要对hashMap的数组进行扩容,最消耗性能:原数组中的数据必须重新计算其在新数组中的位置。
所以在我们使用hashMap时,最好能预知元素的个数,设置数组的长度。
3、get方法分析
从hashMap中get元素时,首先计算key的hashcode,找到在数组中对应的元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。
三、不足之处
伸缩性角度:
每当hashmap扩容的时候需要重新去add entry对象,需要重新hash,然后放入新的entry table数组中。