HashMap数据结构及源码解析
HashMap数据结构
JDK7以前hashmap结构是使用数组和链表组合的一个数据结构,在JDK8增加了一个新特性,当链表的长度大于8的时候会转化为红黑树
(增加这种特性的优势很明显,双向链表的结构如果Hash冲突很严重的话,会导致链表的长度一直增长这样大大减慢了查询的数据,
也有红黑树的劣势,在插入和删除需要进行旋转变色增加了时间和空间复杂度)。
**hashmap 构造函数 **
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
这里只是为负载因子赋值没有做任何初始化操作
hashmap put方法
1、如果为空进行初始化 resize()
创建一个数组对象并返回
2、判断数组的位数
static final int hash(Object key) {//计算hash
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
tab[i = (n - 1) & hash]//计算数组的位置
这一块可能很多人呢会有疑问为什么这么设计,hashmap里面设计所有的数组的长度为2^n,基于此设定我们使用16来举个例子
由上图我们可知通过&运算可以快速算出我们的数组下标,同时这里也存在一个问题我们都知道 object中返回的hash值为int ,java中int占有32个比特位,这样如果hash变化集中在比特位的头部就会导致大量的hash冲突那么通过hash的右位移和异或的组合操作能够将变化由高位降到地位,大大减少hash冲突
3、resize处理
随着hashmap中的元素增多hash冲突也越来越严重,如果里面的值超出 最高值负载因子 会触发resize 进行扩容
扩容的时候为了方便计算数组下标,我们需要在原有的容量基础之上2,同时扩容之后就涉及hash重新计算数组位置的问题,由于我们只是在原有的基础上*2所以对应二进制需要增加一个1,也就意味原本一个hash可能拆分到两个位置上面,拆分又有两种情况 第一种:是链表的话这个比较简单。使用容量&hash 如果为0则认为处于当前位置,如果为1放到新链表。 第二种是红黑树:同样使用容量&hash,拆分后需要判断树的元素是否小于6,如果小于6就将树转化为链表
第一次写博客,根据源码和一些资料整合。。写的有问题,请联系我修改哦