HashMap(一)
基于 jkd1.8 源码认识 HashMap。包含以下内容:
- 扰动函数
- 初始化容量
- 负载因子
扰动函数
在 HashMap 存放元素时候有这样一段代码来处理哈希值,用于优化散列效果:
1 | static final int hash(Object key) { |
1.运算符
- >>>:无符号右移。无论是正数还是负数,高位通通补0;
- ^:异或运算符。相同为 0,不同为 1;
- &:与运算符。同为 1 时才为 1,否则为 0。
2.元素在数组中的位置
1 | // 找到元素在数组中的位置,n为数组长度。 |
3.为什么 HashMap 数组的长度 n 要是2的整数幂
为使 hash 值散列分布在数组的下标当中。
假设我们有一个长度为16的数组,则他的下标范围为 0~15。而任何一个2的整数幂,减1得到的二进制位全部是1。让 hash 值与其就行与运算,结果将保留 hash 值小于数组下标范围的低位。当 hash 足够散列时,得到的结果必为在数组下标内散列的值。
1 | 00100100 10100101 11000100 00100101 // Hash值 |
4.扰动函数里为何无符号右移16位
为使 hash 值的高位也能影响到该元素在数组中的位置,提高散列性。
因为获取元素在数组中的位置时取的是 hash 值在数组下标范围内的低位,则将Hash值的高16位右移并与原Hash值取异或运算(^),混合高16位和低16位的值,会得到一个更加散列的低16位的Hash值。
初始化容量
在 HashMap 的初始化中,有这样一段方法:
1 | public HashMap(int initialCapacity, float loadFactor) { |
其中 threshold 的取值为比 initialCapacity 大的最小2的整数幂:
1 | static final int tableSizeFor(int cap) { |
负载因子
负载因子决定了数据量达到多少了以后,hashmap 会进行扩容,默认值为 0.75。