HashMap
和HashTable
都是 Java 集合中用于存储键值对的数据结构,他们的主要区别有如下几个。
一、同步性
HashMap
是非同步的,多线程环境下是线程不安全的。这使得它在单线程环境下运行相比 HashTable
性能高一些。如果需要在多线程环境中使用 HashMap
,我们可以通过Collections.synchronizedMap()
方法来包装 HashMap
使之同步,或者使用 ConcurrentHashMap
。
HashTable
是同步的,这意味着它是线程安全的,它是所有公共方法都使用了同步锁,这确保了 HashTable
在并发环境下的线程安全。但这也意味着它在性能上比非同步的 HashMap
性能会慢点。
二、空值处理
HashMap
允许一条记录的 key 和多条记录的 value 为null
。HashTable
不允许 key 或 value为null
,否则会抛出NullPointerException
。
三、迭代器
HashMap
的迭代器是fail-fast
迭代器,如果在迭代过程中HashMap
被结构性地修改(增加或删除元素),迭代器会快速失败,抛出ConcurrentModificationException
。HashTable
使用的是枚举 Enumeration 进行迭代的,即获取HashTable
中所有的key,然后遍历 key 集合,在遍历过程中,若HashTable
的结构发生变化时,Enumeration会失效。同时,HashTable
也支持 Iterator。
四、性能
由于 HashTable
是同步的,所以会涉及的锁资源获取和释放的过程,性能较 HashMap
稍微慢些。如果不需要同步,建议使用HashMap
,因为它的数据结构使得它在大多数情况下比HashTable
更快。
即使是在并发环境下,大明哥也建议使用 ConcurrentHashMap
而不是 HashTable
。
五、继承关系
HashMap
继承自AbstractMap
类。HashTable
继承自Dictionary
类。
两者都实现了 Map 接口。
六、初始化和扩容
HashMap
的默认容量为 16,负载因子是 0.75,当HashMap
中元素个数超过容量的75%时,会进行扩容操作,新容量是旧容量的 2 倍。HashTable
的默认容量为 11,负载因子是 0.75,当HashTable
中元素个数超过容量的75%时,会进行扩容操作,新容量是旧容量的 2 倍 + 1。