HashTable(哈希表)是JDK 1.0时就加入的,效率低,因为线程安全
为了提高效率,JDK 1.2加入了HashMap(哈希Map),但是线程不安全。
JDK 1.5 为了解决线程安全的问题,加入了ConcurrentHashMap(并发哈希Map)。
因此一般的选择是:
- 单线程——HashMap
- 多线程——ConcurrentHashMap
特点
- 允许null--null 键值对
- 线程不安全
- 不保证顺序
影响HashMap性能的两个参数
- 初始化容量(capacity)——不要太大,默认16
- 负载因子(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
结论
- 当size>threshold时就会进行再哈希。
- 再哈希后,HashMap就会自动扩容为之前的2倍,并且用一个新的对象代替原来的对象。
由此也可得知,自动扩容是需要消耗资源的,要尽量减少自动扩容的发生。
How HashMap works in java,强烈推荐!【没看】