存的是键值对对象
第一次放元素的时候还没有开辟空间,默认值为16(这个值一定是2的幂次方)
在talbe[0]链表中查找key为null的元素,如果找到,则将value重新赋值给这个元素的value,并返回原来的value。如果没找到,则将这个元素添加到talbe[0]链表的表头。
h右移动再异或的原因:让高位参与运算,防止计算出的数组下标相同的太多(扰动函数)
与运算,算出一个数组下标(与运算比取余要快)
与运算的过程:二进制运算,都为1才为1,否则为0
这就是为什么数组容量一定要是2的幂次方,这样才能保证计算出的数组下标是合法的
计算结果与高位无关,等于传入的hash的最后四位(所以要在上一步计算hash的时候,对hashCode进行位移和异或让高位参与运算)
如果存在,就把当前元素的值覆盖,并返回之前的值
哈希值相等不一定key相同,但哈希值不等key一定不相同
1.1判断是否需要扩容
条件一:size大于扩容的阈值,threshold默认为12(16*0.75)
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 初始容量
static final float DEFAULT_LOAD_FACTOR = 0.75f;//加载因子=填入哈希表中的数据个数/哈希表的长度
条件二:当前的要放入的位置是空的
1.2扩容的方法
创建一个新的数组,长度是原来的两倍
1.2.1 转移元素
如果扩容前:数组容量为16,元素的数组下标为5
那么扩容后:数组容量为32,元素的数组下标为5+16=21或者还是5
扩容转移元素后,链表的顺序会倒过来,出现线程安全问题!
1.2.2重哈希
第一步:判断是否需要重哈希
这个值可以自己配,如果没有配,就是默认值。一般不用配
用e保留现在的头节点
把创建新节点的Entry对象,并放到数组中作为头节点,e作为新节点Entry对象的next域的参数传递
当链表长度大于8并且数组长度大于时,才会转换为红黑树。如果链表长度大于8,但是数组长度小于时,还是会进行扩容操作,不会转换为红黑树。在红黑树的元素小于6的时候会变成链表。
链表转红黑树的原因:TreeNodes的大小大约是普通节点的两倍,最开始使用链表的时候,空间占用是比较少的,而且由于链表短,所以查询时间也没有太大的问题。可是当链表越来越长,需要用红黑树的形式来保证查询的效率。
阈值为8的原因:通常如果 hash 算法正常的话,那么链表的长度也不会很长,那么红黑树也不会带来明显的查询时间上的优势,反而会增加空间负担。所以通常情况下,并没有必要转为红黑树,所以就选择了概率非常小,小于千万分之一概率,也就是长度为 8 的概率,把长度 8 作为转化的默认阈值。
判断该元素的数组下标处是用的红黑树还是链表:
如果是树,遍历红黑树,并加入元素
如果是链表,遍历链表,并用尾插法加入元素(计算链表的长度,判断是否有相同的键)
HashMap线程不安全的原因:
后执行的key和value会把先执行的key和value覆盖
头插法也会出现线程不安全
HashTable线程安全的原理:
把这个entry对象本身作为锁,在操作之前先获取锁,操作完之后再释放锁
效率不高的原因:两个线程的index可能不同,但却要等
分段锁,以Segment对象为锁
初始化后,并发度不会改变了,即Segment数组不会扩容
每个Segment下面的Entry数组的容量相同
扩容的时候是扩容的Entry数组
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- huatuo9.cn 版权所有 赣ICP备2023008801号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务