HashMap 之 再哈希探究

HashTable(哈希表)是JDK 1.0时就加入的,效率低,因为线程安全
为了提高效率,JDK 1.2加入了HashMap(哈希Map),但是线程不安全。
JDK 1.5 为了解决线程安全的问题,加入了ConcurrentHashMap(并发哈希Map)。
 
因此一般的选择是:
  1. 单线程——HashMap
  2. 多线程——ConcurrentHashMap
特点
  1. 允许null--null 键值对
  2. 线程不安全
  3. 不保证顺序
影响HashMap性能的两个参数
  1. 初始化容量(capacity)——不要太大,默认16
  2. 负载因子(load factor)——不要太小,默认0.75
再哈希
 
当哈希表里的entry(键值对)超过一定阈值时,哈希表会进行再哈希(rehash)。再哈希后的哈希表的桶的个数之前的两倍 。(threshold=capacity*factor)
 
验证 
public class HashMapL {
    public static void main(String[] args) {
        HashMap<Integer, Integer> hashMap = new HashMap<>();
        hashMap.put(null, null);  //允许空空键值对
        for(int i=0; i<16; i++){
            hashMap.put(i, i);  //自动装箱
        }
}
下面来一步步的研究
 
HashMap<Integer, Integer> hashMap = new HashMap<>();
 
 
从上图可以看出
 
负载因子——0.75
table——null。尚未分配。了解拉链式哈希表的人就会轻易知道它是一个链表数组。
阈值——0。这个值是在给table分配空间后才会计算
 
hashMap.put(null, null);
 
 
 
从上图可以看到,现在table已经初始化了。
table——拥有一个元素 "null=null",并且从图片最下面可以看到,它是一个包含16个元素的数组
table的id——24
 
继续按下一步,直到size=threshold=12,此刻table的id和之前的一样,还是id=24
 
 
现在再按一次下一步,向HashMap里添加一个元素,让元素的总数size大于阈值threshold
 
 
变化
 
id    24-->104
大小    16-->32
阈值    12-->24
 
结论
  1. 当size>threshold时就会进行再哈希。
  2. 再哈希后,HashMap就会自动扩容为之前的2倍,并且用一个新的对象代替原来的对象。
由此也可得知,自动扩容是需要消耗资源的,要尽量减少自动扩容的发生。
 
How HashMap works in java,强烈推荐!【没看】
 
莫问前程
原文地址:https://www.cnblogs.com/dolphin007/p/4446110.html