HashMap源码分析(jdk1.8),常用api介绍
)
1 HashMap实现原理
HashMap是基于拉链法实现的哈希表(散列表),内部由数组、链表、红黑树实现。
1、数组初始容量默认为16,以2的次方扩充;一是使用足够大的数组防止出现碰撞提高性能,二是为了使用位运算取代模运算。
2、是否需要扩充由负载因子控制,默认0.75,当元素个数到达容量的0.75时就会扩充,可由构造方法传入,越大性能越低空间占用越小,越小性能越高空间占用越高。
3、发生碰撞时,元素改为单向链表类型。当链表长度大于8时,转为红黑树;当链表长度小于6时,转为普通链表。在转换为红黑树之前会先判断一下是否达到阀值,如果达到会先扩充数组。
2 构造方法(注释有解释)
1、 无参(默认初始大小,负载因子)
2、 一个参数(设置初始大小、默认负载因子)
3、 两个参数(设置初始大小、设置负载因子)
会调用tableSizeFor方法,调用目的见下方
4、 一个参数(参数为map对象)
会调用putMapEntries方法,putMapEntries见下方,将传入map的数据复制到当前map中。
3 tableSizeFor方法
通过构造方法指定初始容量,但是容量必须为2的次方(位运算取代模运算),tableSizeFor就是进行实际初始容量的计算。
其原理为:将0 补为 1,最后进一位(+1),减1的这个动作为了避免16这种不需要加1的值(及其他2的次方同理)。
以12为例:只列出右移一位、两位的运算,移位按位或运算为15,加1后位16.
4 putMapEntries (Map<? extends K, ? extends V> m, boolean evict)方法
将一个map,批量添加到当前map中,此方法,在构造方法入参为map时,调用putAll时,调用clone时调用。
5 put方法/putVal方法
调用hash()获取key的hashcode见下方,resize()方法扩容,见下方
6 hash方法(异或运算)
取hashcode进行高位异或运算,在性能、实用性、分布质量上取得一个平衡。(数据均匀分布,减少碰撞发生)
例如:name作为key时,hashcode为3373707,右移16位后位51,异或运算后位3373752
补充:位运算
7 resize方法(扩容)
(1) 首先进行原数据、参数的copy
(2) 进行扩容判断,对于不需要扩容的直接返回
(3) 对扩容后的,进行数据迁移(红黑树未做介绍)
8 get/ getNode方法(取值)
get时,不存在或实际存储的值为null,都会返回null
9 remove/ removeNode方法(移除)
移除map中的属性
10 clear方法(清空)
只是把table[i]的数据置为null,执行效率比不上new一个新的map
11 clone方法(克隆)
12 containsKey方法(是否存在key)
getNode()见get方法