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的结果。

jdk1.8 hashmap源码阅读_第1张图片

怎么减少扩容次数

如果提前知道自己的map中的元素数量的话,比如最多1024个元素,那么可以设置hashmap的容量为1024,也就是node数组的大小为1024,设置装载因子为1,这样即使所有的数据都存入hashmap,也不会触发扩容机制。

为什么node数组的大小是2的n次?

1 可以将hash值& len-1 得到对应的索引位置。

2 在扩容的时候只需要和 新的tablesize 相与即可知道rehash的结果。

jdk1.8 hashmap源码阅读_第2张图片

1.8和1.7的区别

JDK8 中对算哈希值的哈希算法进行了简化以提高运算效率

1.8为啥要用红黑树?

因为链表的插入效率倒是高 头插但是查找效率低,所以用树去做优化, 提升查找和查询的效率。

扩容机制不一样

在使用HashMap的过程中我们应该注意些什么问题?

1. HashMap 的扩容机制是很影响效率的,所以如果事先能确定有多少个元素需要存储,那么建议在初始化HashMap 时对数组的容量也进行初始化,防止扩容。
2. HashMap 中使用了对象的 hashcode 方法,而且很关键,所以再重写对象的 equals 时建议一定要重写hashcode 方法。
3. 如果是用对象作为 HashMap key ,那么请将对象设置为 final ,以防止对象被重新赋值,因为一旦重新赋值其实就代表了一个新对象作为了 key ,因为两个对象的 hashcode 可能不同。

你可能感兴趣的:(Java基础知识,四大件之数据结构和算法,哈希算法,算法)