HashMap的底层数据结构
在JDK8之前,HashMap采取的数据结构是数组+链表,在JDK8之后,引入红黑树。
HashMap的核心是一个动态数组,数组上的每个元素也被称为桶,而桶的索引是通过对键的哈希值进行哈希函数处理得到的。若通过哈希函数处理得到的索引相同,则会产生所谓的哈希冲突,就会在原索引后插入该元素,形成链表。若链表过长,则会影响查找效率,时间复杂度为O(n),若数组长度大于64,且链表长度大于8,则会转换成红黑树,将时间复杂度降为O(logn)。数组的初始容量为16,当他超过阈值时会进行两倍扩容,这个阈值为原大小*负载因子,默认为0.75 。
值得注意的是JDK8之前采用头插法会存在死循环问题,需要加锁影响性能,JDK8之后采用尾插法就解决了这个问题
{在存储元素时,如果发生哈希冲突(即多个元素计算出的哈希值对应的数组索引相同),这些元素会以链表的形式存储在该索引位置。但链表中的元素数量并不计入初始容量或影响扩容的判断。}
HashMap的put流程
-
通过hash方法计算key哈希值
-
数组为空,第一次扩容
-
根据哈希值计算key在数组中的下标
-
若对应下标没有数据,直接插入
-
若对应下标有数据,判断是否相同key,是则覆盖value,否则需要判断是否为树节点,是则插入节点,否则尾插法入链表,插入后链表长度大于等于8,则转化为红黑树。
-
-
所有元素处理完,还需判断是否超过阈值,超过就扩容。
-
只重写 equals 没重写 hashcode,map put 的时候会发生什么?
如果只重写 equals 方法,没有重写 hashcode 方法,那么会导致 equals 相等的两个对象,hashcode 不相等,这样的话,这两个对象会被放到不同的桶中,这样就会导致 get 的时候,找不到对应的值。
HashSet底层原理
其实就是HashMap,固定一个不可变的Object对象,通过键操作