概述
关于HashMap 和 HashTable 的区别, 在这里进行一次总结.
1. 存储结构
HashMap | HashTable |
数组 + 链表/红黑树 | 数组 + 链表 |
HashMap的存储规则:
优先使用数组存储, 如果出现Hash冲突, 将在数组的该位置拉伸出链表进行存储(在链表的尾部进行添加), 如果链表的长度大于设定值后, 将链表转为红黑树.
HashTable的存储规则:
优先使用数组存储, 存储元素时, 先取出下标上的元素(可能为null), 然后添加到数组元素Entry对象的next属性中(在链表的头部进行添加).
出现Hash冲突时, 新元素next属性会指向冲突的元素. 如果没有Hash冲突, 则新元素的next属性就是null
描述的有点模糊, 贴出源码会清晰一点:
Entry<K,V> e = (Entry<K,V>) tab[index]; tab[index] = new Entry<>(hash, key, value, e);
2. 扩容方式
HashMap | HashTable |
oldCap * 2 | oldCap * 2 + 1 |
3. 关于null值
HashMap | HashTable |
key, value 均可以为 null | key, value 均不可以为 null |
4. 线程安全
HashMap | HashTable |
线程不安全 | 线程安全 |
HashMap虽然是线程不安全的, 但还是推荐使用, 因为 HashTable实现线程安全的方式太低效了, 直接在方法上加了 synchronized 关键字来实现的.
我们可以使用 ConcurrentHashMap 来实现线程安全(推荐使用).
或者使用 Collections.synchronizedMap(map); 来实现线程安全(不推荐, 因为内部是使用了synchronized代码块进行控制并发的).