这里将我的阅读源代码后得到的信息以文字不带代码的方式写出来,我的认为有助于本身在面试时候更清晰表达本身想说的东西。面试
HashMap底层实现原理:以数组为主干,链表为分支的方式存储数据。数组中的全部key-value的key的hash值都不相同;链表中,全部key-value的key的hash值相同。算法
具体添加数据(put方法)时,若是根据key计算出的hash值对应的位置没有数据,则将须要添加的数据放在hash值对应的位置上,若是对应的位置已存在数据,则将新数据的next引用指向数组中的key-value数据,而后将新数据放到数组中hash值对应的位置上。固然hash值的算法已经作了足够的优化来尽可能避免不一样的key进行hash计算产生相同的hash值,而且尽可能使数组中的位置可以获得充分的使用,以提升数据获取时的查询效率。数组
得到数据时(get方法)首先根据key的hash值,找到数组中对应的位置,而后经过比较key是否相同,找到对应的value。安全
对于HashMap使用的一些注意点:构造方法有3个:无任何参数;带一个初始容量;带初始容量和负载因子;函数
初始容量简单的说是HashMap中数组最开始没有扩容前的长度,还有一个size是指存储在hashMap中的key-value对数,极限容量为当前容量与负载因子乘积的整数部分。当size值超过极限容量时,HashMap须要扩容。性能
初始容量的计算:调用构造方法时,若是未指定初始容量,则使用默认初始容量为16,源码中以 1<<4 表示,若是指定了初始容量参数,若是参数值为2的n次方值,则该值即为HashMap初始容量,不然为大于该值的最小2的n次方值,如参数值为6,则初始容量为8,参数值为14时,初始容量为16。注意:该值并不是在调用构造方法进行实例化的时候肯定的,是在初次调用put方法时肯定的。也就是说HashMap数组的长度最开始是在初次调用put方法时才肯定的,存储空间也是初次调用put方法时申请的。优化
在这个过程当中,hashMap的极限容量可能发生变化,按照通常的理解,在调用构造方法时指定初始容量,代表后续的操做过程当中,将在该hashMap中存入初始容量个key-value,在构造函数中确实是如此处理的,初始容量的参数值被赋值给极限容量,可是在put方法中进行初始容量再计算时,极限容量从新计算为初始容量与负载因子的乘积,也就是说假如调用构造函数时传入的初始容量为7,负载因子为0.75,在未调用put方法前,hashMap的极限容量都是7,可是当存入第一个key-value后,hashmap的初始容量肯定为8,此时极限容量从新计算为6,那么按照道理来讲,在指定了初始容量以后,并无彻底的杜绝扩容问题,不知道你们有没有发现过这个问题,仍是我有哪些地方理解误差了。线程
扩容:当size 大于等于极限容量时,hashmap会扩容为当前容量(数组长度)的两倍。扩容后,需从新计算各个key-value在数组中的位置。因此hashmap扩容操做是至关消耗性能的。get
hashMap不是线程安全的,若是在使用迭代器的过程当中有其余线程修改了map,将抛出ConcurrentModificationException,这就是所谓fail-fast策略,而其余线程经过其余方式进行操做是没法识别的。源码
以上为小结所有内容,看到有误或不足之处请你们不吝指正,在此很是感谢!