jdk1.8 hashmap源码阅读
目录
hashmap 成员变量
hashmap支持null键吗?为什么?
当扩容的时候,所有元素都会重新计算hash值吗?
怎么减少扩容次数
为什么node数组的大小是2的n次?
1.8和1.7的区别
1.8为啥要用红黑树?
扩容机制不一样
在使用HashMap的过程中我们应该注意些什么问题?
补发一下积灰的文章。
hashmap 成员变量
- DEFAULT_INITIAL_CAPACITY:默认初识表格的容量,值为 16,必须是 2 的 n 次方;
- DEFAULT_LOAD_FACTOR:默认加载因子,值为 0.75;
- loadFactor: 加载因子,可以通过构造函数设置 loadFactory;
- threshold:阈值,当 hash 表的 size 大于这个值得时候,需要进行 resize 扩容操作,公式是 capacity * load factor;
- entrySet:缓存 entrySet() 方法的数据,可以对键或者值进行遍历。
- MIN_TREEIFY_CAPACITY:节点转换成红黑树需要的最少的表格容量,值是 64;
- TREEIFY_THRESHOLD:判断节点是否需要转成红黑树节点,值是 8;
- UNTREEIFY_THRESHOLD:判断是否需要调用 untreeify 方法,值是 6。
hashmap成员变量https://www.jianshu.com/p/c91dc4baf69f
hashmap支持null键吗?为什么?
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
hashmap支持null键,null key 对应的hash值就是0 存放在 第0个桶里面。
而其他key 需要先调用 hashcode 再和右移16位的值进行异或。
可以通过 tab[i = (n - 1) & hash]) 直接访问到该元素在table中处于的位置。
当扩容的时候,所有元素都会重新计算hash值吗?
不会,因为第一次put的时候已经计算过hash值了,在扩容的时候 只需要和 新的tablesize相与即可知道rehash的结果。
怎么减少扩容次数
如果提前知道自己的map中的元素数量的话,比如最多1024个元素,那么可以设置hashmap的容量为1024,也就是node数组的大小为1024,设置装载因子为1,这样即使所有的数据都存入hashmap,也不会触发扩容机制。
为什么node数组的大小是2的n次?
1 可以将hash值& len-1 得到对应的索引位置。
2 在扩容的时候只需要和 新的tablesize 相与即可知道rehash的结果。
1.8和1.7的区别
JDK8
中对算哈希值的哈希算法进行了简化以提高运算效率
1.8为啥要用红黑树?
因为链表的插入效率倒是高 头插但是查找效率低,所以用树去做优化, 提升查找和查询的效率。
扩容机制不一样
在使用HashMap的过程中我们应该注意些什么问题?
1. HashMap
的扩容机制是很影响效率的,所以如果事先能确定有多少个元素需要存储,那么建议在初始化HashMap
时对数组的容量也进行初始化,防止扩容。
2. HashMap
中使用了对象的
hashcode
方法,而且很关键,所以再重写对象的
equals
时建议一定要重写hashcode
方法。
3.
如果是用对象作为
HashMap
的
key
,那么请将对象设置为
final
,以防止对象被重新赋值,因为一旦重新赋值其实就代表了一个新对象作为了
key
,因为两个对象的
hashcode
可能不同。