1 默认加载因子0.75f
2 hash数组默认是16
4 初始化时,如果传入了hash槽的容量大小,不是2的整数次幂,获取刚大于容量的整数次幂
5 key和value都允许null 如果key为null 则数据放在table[0]
6 关于hash因子,如果太大,空间能够充分利用,但是查询慢
如果太小,没存入多少数据就需要开始扩容,但是查询速度快
主要是链表的长度决定的,链表越长,查询速度就慢
8 table[i] 就可以得到改槽下面的链表的头节点
hashMap是单向链表
7 确认数据放在那个槽的算法
static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
static int indexFor(int h, int length) {
return h & (length-1);
}
首先根据Key.hashCode() 得到哈希值,如果调用hash方法得到一个值,最后indexfor返回的值就是hash数组的index
h&(length-1)相当于对length去模,只有在hash数组的大小为2的整数次幂才是如此,比%效率更高,hashtable还是用的%
与运算符 两个都为1才是1 否则是0
|这个运算符是只要有一个是1 就得到1
^ 异或运算符,相同为1,不同为0
~ 取反运算符,对一个数据而言的
所以如果length是2的整数次幂,是偶数,则-1是奇数,奇数的最后一位是1,与运算符的最后一位可能是0,也可能是1,保证数据均匀的分布在hash数组里面
如果length是奇数,则与运算符的最后一位肯定是0,得到的一定是偶数,则hash数组中只有index为偶数的数组里卖弄才能放入数据
8 put和get方法
get相对比较简单,null的话从table[0]中查找,不为null则先获取槽,再遍历
put方法 首先要判断该key是否存在,如果存在,直接替换该key对应的value
如果不存在addentry 获取槽,放在链表的头部,同时要判断size++跟threshold的大小,如果大于总容量的3/4 则进行扩容。扩容所有的数据需要重新放置,很费时间
threshold = (int)(capacity * loadFactor); 槽的数量*因子