Hashtable 不允许空键和空值且线程安全,HashMap 允许一个空键和多个空值但非线程安全;前者是遗留类、默认容量11,后者是集合框架标准实现、默认容量16且容量为2的幂。

Hashtable 不允许空键和空值,HashMap 允许一个空键和任意个空值;Hashtable 是线程同步的(方法加了 synchronized),HashMap 是非同步的,线程不安全。
空键与空值支持不同
Hashtable 对键和值都严格禁止为 null。只要传入 null 键或 null 值,就会立即抛出 NullPointerException。
HashMap 则宽松得多:它允许且仅允许一个 null 键(因为键唯一),但可以有多个 null 值。这是由其内部实现决定的——put(null, value) 会被特殊处理,存入哈希表的第 0 个桶中。
线程安全性差异明显
Hashtable 的所有公共方法(如 put()、get()、containsKey())都用 synchronized 修饰,是天然线程安全的,但代价是性能低——每次操作都要获取整个对象锁。
HashMap 完全不加锁,多线程环境下可能引发数据错乱(如死循环、丢失更新)。若需线程安全,应显式使用:
- Collections.synchronizedMap(new HashMap())(简单包装,仍为全表锁)
- 或更优选择:ConcurrentHashMap(分段锁 / CAS + synchronized,高并发下性能更好)
其他关键区别补充
除了空值和同步,还有几点值得注意:
- Hashtable 是遗留类,继承自 Dictionary(已废弃),而 HashMap 实现 Map 接口,是 Java 集合框架标准成员
- Hashtable 默认初始容量为 11,扩容为 old * 2 + 1;HashMap 默认为 16,扩容为 old * 2,且要求容量始终是 2 的幂
- Hashtable 的迭代器是 fail-fast 的,但早期版本中部分方法(如 elements())返回的枚举器不是;HashMap 迭代器统一为 fail-fast

















