HashMap
底层在JDK1.7是用数组+链表,JDK1.8以后是用数组+链表+红黑树。
HashMap继承了AbstractMap抽象类和实现了Map接口、Cloneable接口和serializable接口。
当插入一个数据时,计算key的hash值,再将hash值对数组长度取余,来确定索引。
hash值的计算方法:(h=key.hashcode())^(h>>>16) 无符号右移16位的原因是避免数组很小时,hashcode高位变化对索引不产生影响,导致哈希碰撞。
当索引上为空时,直接插入。当索引上有值时,比较hash值是否相等,若相等再比较Key值是否相等,都相等则新的value值取代旧的value值,否则在下面插入。
在数组长度大于64且链表长度大于8时链表转换为红黑树。红黑树大小小于6时转换为链表。
当HashMap大小>数组长度*加载因子时,数组长度会扩充成两倍。0.75是最合适的加载因子
数组长度只能是2的次方,因为底层实现hash值取余逻辑的方法是hash值与数组长度-1进行按位与,所以数组长度为其他值时不能高效的实现取余操作。
若自定义长度,则会转换成大于自定义长度且最接近的2的次方。
转换为红黑树的边界值是8的原因是,根据泊松分布,链表达到8的概率很小很小,是时间和空间的权衡。
HashMap构造方法传参是Map时,构造的HashMap数组长度计算方法为:map的大小size/默认加载因子+1,再取大于其的最小2的次方作为数组长度。这里+1是因为避免扩容,因为不加1的话新的HashMap可能已经是扩容的边界了,随便加个值就要扩容了,影响性能。