其实HashMap中的逻辑不算复杂,如果看懂了我之前对于HashMap中核心方法源码的分析这些问题应该都能回答上来。
1. HashMap的内部数据结构
数组 + 链表/红黑树
2. HashMap允许空键空值么
HashMap最多只允许一个键为Null(多条会覆盖),但允许多个值为Null
3. 影响HashMap性能的重要参数
初始容量:创建哈希表(数组)时桶的数量,默认为 16
负载因子:哈希表在其容量自动增加之前可以达到多满的一种尺度,默认为 0.75
4. HashMap的工作原理
HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象
5. HashMap中put()的工作原理
6.HashMap 的底层数组长度为何总是2的n次方
HashMap根据用户传入的初始化容量,利用无符号右移和按位或运算等方式计算出第一个大于该数的2的幂。
- 使数据分布均匀,减少碰撞
- 当length为2的n次方时,h&(length - 1) 就相当于对length取模,而且在速度、效率上比直接取模要快得多
1.8中做了哪些优化优化?
- 数组+链表改成了数组+链表或红黑树
- 链表的插入方式从头插法改成了尾插法
- 扩容的时候1.7需要对原数组中的元素进行重新hash定位在新数组的位置,1.8采用更简单的判断逻辑,位置不变或索引+旧容量大小
- 在插入时,1.7先判断是否需要扩容,再插入,1.8先进行插入,插入完成再判断是否需要扩容
7.HashMap线程安全方面会出现什么问题
- 在jdk1.7中,在多线程环境下,扩容时会造成环形链或数据丢失。
- 在jdk1.8中,在多线程环境下,会发生数据覆盖的情况
8. 为什么1.8改用红黑树
比如某些人通过找到你的hash碰撞值,来让你的HashMap不断地产生碰撞,那么相同key位置的链表就会不断增长,当你需要对这个HashMap的相应位置进行查询的时候,就会去循环遍历这个超级大的链表,性能及其地下。java8使用红黑树来替代超过8个节点数的链表后,查询方式性能得到了很好的提升,从原来的是O(n)到O(logn)。