HashMap 和 Hashtable 都是 Java 中用于存储键值对的数据结构,它们都实现了 Map 接口,但存在以下几个主要区别:
- 线程安全性:
-
HashTable
是线程安全的,其方法都是同步的(即在多线程环境下使用时会自动进行内部加锁),因此多个线程可以安全地同时读写 HashTable,但可能会牺牲一定的性能。 -
HashMap
在设计上并没有考虑线程安全问题,因此在多线程环境下如果不采取适当的同步控制措施,直接并发访问可能会导致数据不一致或出现意外的行为。
- null 值处理:
-
HashTable
不允许插入null
键和null
值,试图插入null
会抛出NullPointerException
。 -
HashMap
允许插入null
键和null
值,但是只有一个null
键和任意数量的null
值。
- 效率:
- 因为不需要进行线程同步,所以单线程环境下 HashMap 的操作通常比 HashTable 更快。
- 迭代器行为:
- 当一个 HashMap 或 HashTable 在迭代过程中被修改(如添加、删除元素)时,
Hashtable
的Iterator
会抛出ConcurrentModificationException
异常。 - 虽然 HashMap 在某些版本的 Java 也会抛出此异常,但在 Java 5 及以后引入了
ConcurrentHashMap
类,并且对 HashMap 进行了改进,提供了 fail-fast(快速失败)迭代器机制,这意味着如果在迭代期间结构发生变化,则迭代器会立即抛出异常。
- 哈希算法:
- 虽然具体的实现细节可能随 Java 版本有所变化,但两者都会根据键的哈希码来计算存储位置。关于哈希值的计算方式,早期版本中可能有所不同,不过在现代 Java 版本中,两者的哈希策略和冲突解决方法已经很相似。
- 历史及现代实践:
-
Hashtable
是较早出现在 Java 中的类,在集合框架的发展过程中,由于线程安全方面的限制以及性能因素,逐渐被非线程安全但性能更高的HashMap
取代,尤其是在单线程应用或者需要线程安全但又追求高性能的场景下,会选择使用ConcurrentHashMap
替代HashTable
。