JDK8之后HashMap的结构
- JDK8之前,JDK以及更老版本,HashMap就是数组+链表
- JDK8之后,HashMap为数组+链表+红黑树(冲突严重的链表会被"树化",将链表转为红黑树,提高冲突严重的链表的查询效率)
关于HashMap源码中属性的解读
put方法解读
hash方法
哈希函数设计理念:经过hash运算得到的值尽可能的平均
此时得到的值还不是当前数组的索引,只是经过hash运算得到的应该比较均衡的值
将上一步得到的key的hash值和当前哈希表长度-1进行&运算就可以得到索引值
相当于hash%数组长度(n)
注意:前提是n必须为2^n (初始化的哈希桶数量必须为2^n)
putVal方法
put方法核心流程小结
I.若HashMap还未初始化,先进行哈希表的初始化操作(默认初始化为16个桶)
II.对传入的key值做hash,得出要存放该元素的桶编号
a.若没有发生碰撞,即头结点为空,将该节点直接存放到桶中作为头结点
b.若发生碰撞
1.此桶中的链表已经树化,将节点构造为树节点后加入红黑树
2.链表还未树化,将节点作为链表的最后一个节点入链表
III.若哈希表中存在key值相同的元素,替换最新的value值
IV.若桶满了(rize++ 是否大于threshold),调用resize()扩容哈希表。 thresholed = 容量(默认16) * 负载因子 (默认0.75)
HashMap的构造方法
无参构造
构造时并没初始化数组
默认值为null
数组内部还没有初始化,只有第一次调用put方法时才初始化内部哈希桶数组。(懒加载模式)
第一次使用(添加)时才初始化相应的内存
有参构造
reszie()方法
既是扩容方法又是初始化方法,在resize()方法中进行哈希桶数组的初始化操作
Set集合和Map集合的关系
- Set集合的子类实际上在存储元素时就是保存在Map集合的Key中,这也是Set元素不可重复的原因
- HashSet可以保存Null,因为HashMap的Key可以为Null
- TreeSet不能保存Null,因为TreeMap的key不能为Null