1.7-hashtable=数组(基础)+链表>=1.8=数组+链表+红黑树
HashMap的大小->不考虑hash碰撞和扩容->数组的大小
new HashMap();如果不写构造参数默认大小是16
DEFAULT_INITIAL_CAPACITY = 1 << 4; Hash表默认初始容量 (2的4次方)
如果说写了初始容量:11,它的容量就是11吗?
hashMap的get和put操作,使用的是数组格式的时间复杂度都是O(1);
key.hashcode=不确定>16---有符号的整型值(可能为负数),但是数组的索引下表只能在0-15,那怎么能保证hashcode值在0-15之内?
hashcode%16=[0-15];
数组的元素位置是百分之百被利用?
不一定的,因为有hash会碰撞,因为key是一个范型,是一个随机类型
为了解决hash冲突问题->引入链表,链表的时间复杂度是O(n)
如果又有个对象在同一个数组索引上发生hash冲突,java7采用头部插入法
hashMap并不是用取模来来计算索引位置,而是用位运算!
效率:位运算>% 因为位运算最接近我们的机器语言,为了让hashcode更加散裂,尽可能的减少hash碰撞
并没有说hashMap的容量一定是16,那16怎么来的呢?
因为在编写hashMap的工程师认为大多数情况,默认值16这种容量用的比较多,并没有一定要求是16
但是必须是2的指数次幂,如果传的初始化值不是2的指数次幂,它会帮你转化?
1.必须最接近size
2.必须大于size
3.必须是2的指数次幂
为什么要一定转成2的指数次幂呢?
1.判断数组是否为空,如果为空创建新的数组 //长度必须为2的整数次幂
2.判断key值是否为null,如果为null,直接存到数组下标为0的位置
3.根据key算出key的hashcode,并进行一些运运算,为了让hashcode更加散列,尽可能的减少hash碰撞
4.根据hashcode和数组长度,通过与运算找出数组索引的下标位置
5.根据索引所在位置,遍历所在索引的链表,如果hash,key相等的话,直接替换那个节点的值
1当size大于或者等于数组的初始化容量*0.75的时候并且当前索引所在的数组不为null的时候进行扩容
2.扩容的大小必须为2的整数次幂,所以扩容为2倍
2.1.new一个大小为扩容后数组
2.2.把老数组的数据移动到新数组
2.2.1遍历以前的旧数组
2.2.2遍历每个数组上的链表
2.2.3根据链表上节点key的hash和新数组的长度再一次进行与运算
2.2.4更新数据节点(头插法扩容之后数据链会反过来)
2.2.4多线程情况会写形成死环
java>1.8 引入红黑树
容量>=64才会转红黑树,否者优先扩容 只有等链表过长,阈值 TREEIFY_THRESHOLD = 8;不是代表链表的长度,链表长度是大于8的,链接表长度为9的时候转到红黑树
为什么扩容因子为什么是0.75呢?因为是牛顿的哥哥牛逼根据牛顿二项式推导出来的是0.6913,根据空间和时间取了0.75是最优
为什么当链表长度为8的时候转红黑树呢?
泊松分布:概率学问题,可以得到概率学数值
采用高低位拆分转移方式,避免了链表环的产生。