HashMap
Hash理解(因为和hash相关,所以叫hashmap)
什么是hash
把任意长度的输入通过一个hash算法以后映射成为一个固定长度的输出。
问题:两个value值经过hash函数以后可能得到两个相同的hash值,也就是会发生hash冲突。
hash冲突可以避免吗?
答:理论上是不可以避免的,举个例子,抽屉原理,鸽巢原理,比如有10个苹果,9个抽屉,最终一定有一个抽屉里边的苹果数量是大于1的,是不可避免的,只能尽量避免。
好的hash算法的特点,要考虑些什么问题?
1效率高:对于长文本也能高效的计算出hash值
2不能逆推出原文?
3对于不同的输入,保证输出也是不同的
4hash出的值要尽可能分散,在table大部分的slot处于空闲状态的时候,尽可能降低hash冲突
hashMap底层的数据结构
jdk的底层是使用了数组+链表+红黑树实现。
每一个数据单元都是一个Node结构,Node结构中有key字段,有value字段,还有next字段,还有hash字段,hash字段用于解决hash冲突的时候的比较,next字段用于解决hash冲突的时候,当前桶位的node与冲突node连成一个链表要用的字段。
hashMap的初始数组长度
16
hashMap的初始化
散列表采用的是懒加载的模式,不会在new HashMap的时候进行加载,会在调用第一次put的时候进行加载。
HashMap map = new HashMap(); // 伪初始化
map.put(“键”,“值”); // 真初始化
在调用put函数的时候,如果发现table是null就调用resize()进行初始化
负载因子作用
0.75f
负载因子的作用:计算扩容的阈值
扩容时机
使用无参构造方法创建的HashMap,默认情况下的扩容阈值就是16*0.75 = 12
链表转化为红黑树时机
链表转化为红黑树的2个时机:
1链表长度等于8
2当前散列表数组的长度已经达到64
否则:就算slot的链表长度大于8,也不会从链表转为红黑树,而仅仅会触发一次散列表扩容,resize()
Node内部的hash字段是由key.hashCode()生成的吗?
Node内部的hash字段是由key.hashCode()生成的吗?不是的。
Hash值是由key对象的hashCode二次加工得到的。
加工原则:key的hashcode的高16位异或key的hashcode的低16位得到的一个新