Java 中的 HashMap
和 Hashtable
有什么区别?
哪个对非线程应用程序更有效?
ConcurrentMap
,因为问题说“非线程应用程序”意味着线程/并发不是问题。
HashTable
传统上只是因为它的部分线程保护而被选择。但这已被 ConcurrentHashMap
消除,所以它通常被认为是退休了。通常建议在 HashMap
或 ConcurrentHashMap
之间进行选择。” 我相信这是一个明智的评论,如果这是她的意思。
Java 中的 HashMap
和 Hashtable
有几个区别:
Hashtable 是同步的,而 HashMap 不是。这使得 HashMap 更适合非线程应用程序,因为非同步对象通常比同步对象执行得更好。 Hashtable 不允许空键或空值。 HashMap 允许一个空键和任意数量的空值。 HashMap 的子类之一是 LinkedHashMap,因此如果您想要可预测的迭代顺序(默认为插入顺序),您可以轻松地将 HashMap 换成 LinkedHashMap。如果您使用 Hashtable,这将不会那么容易。
由于同步对您来说不是问题,因此我建议您使用 HashMap
。如果同步成为问题,您还可以查看 ConcurrentHashMap
。
请注意,许多答案都表明 Hashtable 是同步的。在实践中,这给你带来的收益很少。访问器/修改器方法上的同步将停止两个线程同时从映射中添加或删除,但在现实世界中,您通常需要额外的同步。
一个非常常见的习惯用法是“先检查然后放”——即在Map
中查找一个条目,如果它不存在则添加它。无论您使用 Hashtable
还是 HashMap
,这绝不是一个原子操作。
可以通过以下方式获得等效同步的 HashMap
:
Collections.synchronizedMap(myMap);
但是要正确实现此逻辑,您需要对表单进行额外的同步:
synchronized(myMap) {
if (!myMap.containsKey("tomato"))
myMap.put("tomato", "red");
}
即使遍历 Hashtable
的条目(或 Collections.synchronizedMap
获得的 HashMap
)也不是线程安全的,除非您还保护 Map
不通过额外的同步被修改。
ConcurrentMap
接口的实现(例如 ConcurrentHashMap
)通过包含 线程安全的 check-then-act 语义解决了其中的一些问题,例如:
ConcurrentMap.putIfAbsent(key, value);
Hashtable
被视为遗留代码。 Hashtable
没有什么是不能使用 HashMap
或 HashMap
派生的,所以对于新代码,我看不出有任何理由回到 Hashtable
。
这个问题经常在面试中被问到,以检查候选人是否理解集合类的正确用法以及是否知道可用的替代解决方案。
HashMap 类与 Hashtable 大致等价,不同之处在于它是非同步的并且允许空值。 (HashMap 允许空值作为键和值,而 Hashtable 不允许空值)。 HashMap 不保证地图的顺序会随着时间的推移保持不变。 HashMap 是非同步的,而 Hashtable 是同步的。 HashMap 中的迭代器是故障安全的,而 Hashtable 的枚举器则不是,如果任何其他线程通过添加或删除除 Iterator 自己的 remove() 方法之外的任何元素在结构上修改映射,则抛出 ConcurrentModificationException。但这不是保证行为,JVM 会尽最大努力来完成。
一些重要术语的注意事项:
同步意味着只有一个线程可以在一个时间点修改哈希表。基本上,这意味着任何线程在对 Hashtable 执行更新之前都必须获取对象上的锁,而其他线程将等待锁被释放。故障安全在迭代器的上下文中是相关的。如果在集合对象上创建了一个迭代器,并且某个其他线程试图“结构化地”修改集合对象,则会引发并发修改异常。其他线程可以调用 set 方法,因为它不会“结构地”修改集合。但是,如果在调用 set 之前,集合已经在结构上进行了修改,则会抛出 IllegalArgumentException。结构修改是指删除或插入可以有效改变地图结构的元素。
HashMap
可以通过
Map m = Collections.synchronizeMap(hashMap);
Map 提供 Collection 视图,而不是通过 Enumeration 对象直接支持迭代。集合视图极大地增强了界面的表现力,这将在本节后面讨论。 Map 允许您迭代键、值或键值对; Hashtable
不提供第三个选项。 Map 提供了一种在迭代过程中删除条目的安全方法; Hashtable
没有。最后,Map 修复了 Hashtable
界面中的一个小缺陷。 Hashtable
有一个名为 contains 的方法,如果 Hashtable
包含给定值,则该方法返回 true。鉴于其名称,如果 Hashtable
包含给定键,您会期望此方法返回 true,因为该键是 Hashtable
的主要访问机制。 Map 接口通过重命名方法 containsValue
消除了这种混淆来源。此外,这提高了界面的一致性 - containsValue
与 containsKey
平行。
地图界面
HashMap
上没有 set
操作。 3) 如果之前有更改,put(...)
操作不会抛出 IllegalArgumentException
。 4) 如果您更改映射,HashMap
also 的快速失败行为会发生。 5) 保证快速失败的行为是。 (如果您进行并发修改,则不能保证 HashTable
的行为。实际行为是......不可预测的。)
Hashtable
也不保证地图元素的顺序会随着时间的推移保持稳定。 (您可能将 Hashtable
与 LinkedHashMap
混淆了。)
thing.set(thing.get() + 1);
,它经常让新手感到惊讶,因为它完全不受保护,特别是如果 get()
和 set()
是同步方法。他们中的许多人都在期待魔法。
HashMap
:Map
接口的实现,它使用哈希码来索引数组。 Hashtable
:嗨,1998 年打来的电话。他们希望他们的收藏 API 回来。
不过说真的,您最好完全远离 Hashtable
。对于单线程应用程序,您不需要额外的同步开销。对于高度并发的应用程序,偏执的同步可能会导致饥饿、死锁或不必要的垃圾收集暂停。就像 Tim Howland 指出的那样,您可以改用 ConcurrentHashMap
。
请记住,在引入 Java 集合框架 (JCF) 之前,HashTable
是遗留类,后来经过改进以实现 Map
接口。 Vector
和 Stack
也是如此。
因此,在新代码中始终远离它们,因为正如其他人所指出的那样,JCF 中总是有更好的选择。
这是您会发现有用的 Java collection cheat sheet。请注意,灰色块包含遗留类 HashTable、Vector 和 Stack。
https://i.stack.imgur.com/PyflH.png
已经发布了许多好的答案。我正在添加一些新观点并对其进行总结。
HashMap
和 Hashtable
都用于以键值形式存储数据。两者都使用散列技术来存储唯一键。但是下面给出的 HashMap 和 Hashtable 类之间存在许多差异。
哈希映射
HashMap 是非同步的。它不是线程安全的,如果没有适当的同步代码,就不能在多个线程之间共享。 HashMap 允许一个空键和多个空值。 HashMap 是 JDK 1.2 中引入的一个新类。 HashMap 很快。我们可以通过调用此代码 Map m = Collections.synchronizedMap(HashMap); 使 HashMap 同步。 HashMap被Iterator遍历。 HashMap 中的迭代器是快速失败的。 HashMap 继承 AbstractMap 类。
哈希表
哈希表是同步的。它是线程安全的,可以与许多线程共享。 Hashtable 不允许空键或值。 Hashtable 是一个遗留类。哈希表很慢。 Hashtable 是内部同步的,不能不同步。 Hashtable 由 Enumerator 和 Iterator 遍历。 Hashtable 中的枚举器不是快速失败的。 Hashtable 继承 Dictionary 类。
进一步阅读What is difference between HashMap and Hashtable in Java?
https://i.stack.imgur.com/sDoih.png
除了 izb 所说的,HashMap
允许空值,而 Hashtable
不允许。
另请注意,Hashtable
扩展了 Dictionary
类,作为 Javadocs 状态,已过时并已被 Map
接口取代。
Hashtable
与 HashMap
类似,并且具有类似的界面。建议您使用 HashMap
,除非您需要支持旧版应用程序或需要同步,因为 Hashtables
方法已同步。因此,在您的情况下,由于您不是多线程,HashMaps
是您最好的选择。
Hashtable
是同步的,而 HashMap
不是。这使得 Hashtable
比 Hashmap
慢。
对于单线程应用程序,请使用 HashMap
,因为它们在功能方面是相同的。
hashtable 和 hashmap 之间的另一个关键区别是 HashMap 中的 Iterator 是快速失败的,而 Hashtable 的枚举器不是,并且如果任何其他线程通过添加或删除除 Iterator 自己的 remove() 方法之外的任何元素在结构上修改映射,则抛出 ConcurrentModificationException。但这不是保证行为,JVM 会尽最大努力完成。”
我的来源:http://javarevisited.blogspot.com/2010/10/difference-between-hashmap-and.html
除了这里已经提到的所有其他重要方面之外,Collections API(例如 Map 接口)一直在修改以符合 Java 规范的“最新和最伟大”的补充。
例如,比较 Java 5 Map 迭代:
for (Elem elem : map.keys()) {
elem.doSth();
}
与旧的 Hashtable 方法相比:
for (Enumeration en = htable.keys(); en.hasMoreElements(); ) {
Elem elem = (Elem) en.nextElement();
elem.doSth();
}
在 Java 1.8 中,我们还被承诺能够像在良好的旧脚本语言中一样构造和访问 HashMap:
Map<String,Integer> map = { "orange" : 12, "apples" : 15 };
map["apples"];
更新:不,他们不会登陆 1.8... :(
Are Project Coin's collection enhancements going to be in JDK8?
Hashtable
既不实现 Map
也不实现 Iterable
(这是“新”foreach 语法所必需的)。但是,Hashtable.keySet()
返回确实允许该语法的 Set
。
Map
...很高兴在这么多年的无知之后得到纠正
HashTable 是同步的,如果你在单线程中使用它,你可以使用 HashMap,它是一个非同步版本。未同步的对象通常性能更高一些。顺便说一句,如果多个线程同时访问一个HashMap,并且至少有一个线程在结构上修改了map,那么它必须在外部同步。您可以使用以下方法将未同步的地图包装在同步地图中: Map m = Collections.synchronizedMap(new HashMap(...));
HashTable 只能包含非空对象作为键或值。 HashMap 可以包含一个空键和空值。
Map 返回的迭代器是快速失败的,如果在创建迭代器后的任何时间对映射进行结构修改,除了通过迭代器自己的 remove 方法之外的任何方式,迭代器都会抛出 ConcurrentModificationException。因此,面对并发修改,迭代器快速而干净地失败,而不是在未来不确定的时间冒任意的、非确定性的行为。而 Hashtable 的键和元素方法返回的枚举不是快速失败的。
HashTable 和 HashMap 是 Java Collections Framework 的成员(从 Java 2 平台 v1.2 开始,HashTable 被改造以实现 Map 接口)。
HashTable 被认为是遗留代码,如果需要线程安全的高并发实现,文档建议使用 ConcurrentHashMap 代替 Hashtable。
HashMap 不保证返回元素的顺序。对于 HashTable 我想它是相同的,但我不完全确定,我没有找到明确说明这一点的资源。
HashMap
和 Hashtable
在算法上也存在显着差异。以前没有人提到过这一点,所以这就是我提出它的原因。 HashMap
将构建一个大小为 2 次方的哈希表,动态增加它,使您在任何存储桶中最多有大约 8 个元素(碰撞),并且对于一般元素类型会很好地搅拌元素。但是,如果您知道自己在做什么,Hashtable
实现可以更好更精细地控制散列,也就是说,您可以使用最接近您的值域大小的素数来修复表大小,这将导致比 HashMap 更好的性能即在某些情况下更少的碰撞。
与此问题中广泛讨论的明显差异不同,我将 Hashtable 视为“手动驾驶”汽车,您可以更好地控制散列,而 HashMap 作为“自动驾驶”对应物,通常会表现良好。
Collection
(有时称为容器)只是将多个元素组合成一个单元的对象。 Collection
用于存储、检索、操作和交流聚合数据。集合框架W 是用于表示和操作集合的统一架构。
HashMap
JDK1.2
和 Hashtable JDK1.0
都用于表示一组以 <Key, Value>
对表示的对象。每个 <Key, Value>
对称为 Entry
对象。条目集合由 HashMap
和 Hashtable
的对象引用。集合中的键必须是唯一的或独特的。 [因为它们用于检索特定键的映射值。集合中的值可以重复。]
« 超类、遗产和集合框架成员
Hashtable 是 JDK1.0
中引入的遗留类,它是 Dictionary 类的子类。从 JDK1.2
Hashtable 被重新设计以实现 Map interface 以使其成为集合框架的成员。 HashMap 是 Java 集合框架的成员,从它在 JDK1.2
中的介绍开始。 HashMap 是 AbstractMap 类的子类。
public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, Serializable { ... }
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { ... }
« 初始容量和负载系数
容量是哈希表中的桶数,初始容量只是哈希表创建时的容量。请注意,哈希表是开放的:对于“hash
collision
”,单个存储桶存储多个条目,必须按顺序搜索。负载因子是哈希表在其容量自动增加之前允许达到的程度的度量。
HashMap 使用默认初始容量 (16) 和默认加载因子 (0.75) 构造一个空哈希表。其中 Hashtable 构造具有默认初始容量 (11) 和负载因子/填充率 (0.75) 的空哈希表。
https://i.stack.imgur.com/AerdR.png
« 哈希冲突情况下的结构修改
HashMap
、Hashtable
在哈希冲突的情况下,它们将映射条目存储在链表中。 从 Java8 到 HashMap
如果哈希桶增长超过某个阈值,该桶将从 linked list of entries to a balanced tree
切换。它将最坏情况的性能从 O(n) 提高到 O(log n)。将列表转换为二叉树时,哈希码用作分支变量。如果同一个桶中有两个不同的哈希码,一个被认为更大,在树的右边,另一个在左边。但是当两个哈希码相等时,HashMap
假定键是可比较的,并比较键以确定方向,以便可以保持某种顺序。制作 HashMap
comparable 的键是一个很好的做法。在添加条目时,如果桶大小达到 TREEIFY_THRESHOLD = 8
,则将条目链表转换为平衡树,在删除小于 TREEIFY_THRESHOLD
且最多 UNTREEIFY_THRESHOLD = 6
的条目时,会将平衡树重新转换为条目链表。 Java 8 SRC、stackpost
« 集合视图迭代,Fail-Fast 和 Fail-Safe
+--------------------+-----------+-------------+
| | Iterator | Enumeration |
+--------------------+-----------+-------------+
| Hashtable | fail-fast | safe |
+--------------------+-----------+-------------+
| HashMap | fail-fast | fail-fast |
+--------------------+-----------+-------------+
| ConcurrentHashMap | safe | safe |
+--------------------+-----------+-------------+
Iterator
本质上是快速失败的。即,如果在迭代时修改了集合而不是它自己的 remove() 方法,它会抛出 ConcurrentModificationException。其中 Enumeration
本质上是故障安全的。如果在迭代时修改了集合,它不会抛出任何异常。
根据 Java API Docs,Iterator 总是优于 Enumeration。
注意:枚举接口的功能与迭代器接口相同。此外,Iterator 添加了一个可选的删除操作,并且具有更短的方法名称。新的实现应该考虑使用迭代器而不是枚举。
在 Java 5 introduced ConcurrentMap Interface 中:ConcurrentHashMap
- 由哈希表支持的高度并发、高性能 ConcurrentMap
实现。此实现在执行检索时从不阻塞,并允许客户端选择更新的并发级别。它旨在替代 Hashtable
:除了实现 ConcurrentMap
,它还支持 Hashtable
特有的所有“旧”方法。
每个 HashMapEntrys 值都是可变的,从而确保竞争修改和后续读取的细粒度一致性;每次读取都反映了最近完成的更新
迭代器和枚举是故障安全的 - 反映自迭代器/枚举创建以来某个时刻的状态;这允许以降低一致性为代价同时读取和修改。它们不会抛出 ConcurrentModificationException。但是,迭代器被设计为一次只能由一个线程使用。
与 Hashtable 类似,但与 HashMap 不同,此类不允许将 null 用作键或值。
public static void main(String[] args) {
//HashMap<String, Integer> hash = new HashMap<String, Integer>();
Hashtable<String, Integer> hash = new Hashtable<String, Integer>();
//ConcurrentHashMap<String, Integer> hash = new ConcurrentHashMap<>();
new Thread() {
@Override public void run() {
try {
for (int i = 10; i < 20; i++) {
sleepThread(1);
System.out.println("T1 :- Key"+i);
hash.put("Key"+i, i);
}
System.out.println( System.identityHashCode( hash ) );
} catch ( Exception e ) {
e.printStackTrace();
}
}
}.start();
new Thread() {
@Override public void run() {
try {
sleepThread(5);
// ConcurrentHashMap traverse using Iterator, Enumeration is Fail-Safe.
// Hashtable traverse using Enumeration is Fail-Safe, Iterator is Fail-Fast.
for (Enumeration<String> e = hash.keys(); e.hasMoreElements(); ) {
sleepThread(1);
System.out.println("T2 : "+ e.nextElement());
}
// HashMap traverse using Iterator, Enumeration is Fail-Fast.
/*
for (Iterator< Entry<String, Integer> > it = hash.entrySet().iterator(); it.hasNext(); ) {
sleepThread(1);
System.out.println("T2 : "+ it.next());
// ConcurrentModificationException at java.util.Hashtable$Enumerator.next
}
*/
/*
Set< Entry<String, Integer> > entrySet = hash.entrySet();
Iterator< Entry<String, Integer> > it = entrySet.iterator();
Enumeration<Entry<String, Integer>> entryEnumeration = Collections.enumeration( entrySet );
while( entryEnumeration.hasMoreElements() ) {
sleepThread(1);
Entry<String, Integer> nextElement = entryEnumeration.nextElement();
System.out.println("T2 : "+ nextElement.getKey() +" : "+ nextElement.getValue() );
//java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextNode
// at java.util.HashMap$EntryIterator.next
// at java.util.Collections$3.nextElement
}
*/
} catch ( Exception e ) {
e.printStackTrace();
}
}
}.start();
Map<String, String> unmodifiableMap = Collections.unmodifiableMap( map );
try {
unmodifiableMap.put("key4", "unmodifiableMap");
} catch (java.lang.UnsupportedOperationException e) {
System.err.println("UnsupportedOperationException : "+ e.getMessage() );
}
}
static void sleepThread( int sec ) {
try {
Thread.sleep( 1000 * sec );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
« 空键和空值
HashMap
最多允许一个空键和任意数量的空值。其中 Hashtable
甚至不允许单个空键和空值,如果键或值为空,则抛出 NullPointerException。 Example
« 同步,线程安全
Hashtable
在内部同步。因此,在多线程应用程序中使用 Hashtable
是非常安全的。其中 HashMap
未在内部同步。因此,在没有外部同步的多线程应用程序中使用 HashMap
是不安全的。您可以使用 Collections.synchronizedMap()
方法在外部同步 HashMap
。
“ 表现
由于 Hashtable
是内部同步的,因此 Hashtable
比 HashMap
稍慢。
@看
红黑树是一种自平衡二叉搜索树
Java 8 中 HashMap 的性能改进
对于线程应用程序,您通常可以使用 ConcurrentHashMap - 取决于您的性能要求。
1.Hashmap
和 HashTable
都存储键和值。
2.Hashmap
可以将一个密钥存储为null
。 Hashtable
无法存储 null
。
3.HashMap
未同步,但 Hashtable
已同步。
4.HashMap
可以与Collection.SyncronizedMap(map)
同步
Map hashmap = new HashMap();
Map map = Collections.SyncronizedMap(hashmap);
除了已经提到的差异之外,需要注意的是,从 Java 8 开始,HashMap
将每个桶中使用的 Nodes(链表)动态替换为 TreeNodes(红黑树),因此即使存在高哈希冲突,最坏的情况搜索时是
Hashtable
中 HashMap
Vs O(n) 的 O(log(n))。
*上述改进尚未应用于 Hashtable
,而仅应用于 HashMap
、LinkedHashMap
和 ConcurrentHashMap
。
仅供参考,目前,
TREEIFY_THRESHOLD = 8 :如果一个桶包含超过 8 个节点,则将链表转换为平衡树。
UNTREEIFY_THRESHOLD = 6 :当存储桶变得太小(由于删除或调整大小)时,树将转换回链表。
HashTable 和 HashMap 有 5 个基本区别。
Maps 允许您迭代和检索键、值以及键值对,而 HashTable 不具备所有这些功能。在 Hashtable 中有一个函数 contains(),使用起来非常混乱。因为 contains 的意思略有偏差。是指包含键还是包含值?很难理解。同样,在 Maps 中,我们有 ContainsKey() 和 ContainsValue() 函数,它们非常容易理解。在 hashmap 中,您可以在迭代时安全地删除元素。因为在哈希表中是不可能的。 HashTables 默认是同步的,所以它可以很容易地与多个线程一起使用。 HashMaps 默认是不同步的,所以只能在单线程中使用。但是您仍然可以使用 Collections util 类的 synchronizedMap(Map m) 函数将 HashMap 转换为同步。 HashTable 不允许空键或空值。 HashMap 允许一个空键和多个空值。
我的小贡献:
Hashtable 和 HashMap 之间的第一个也是最显着的区别是,HashMap 不是线程安全的,而 Hashtable 是线程安全的集合。 Hashtable 和 HashMap 之间的第二个重要区别是性能,因为 HashMap 不同步,它的性能比 Hashtable 更好。 Hashtable 与 HashMap 的第三个区别是 Hashtable 是过时的类,您应该使用 ConcurrentHashMap 代替 Java 中的 Hashtable。
HashMap:它是 java.util 包中的一个类,用于以键值格式存储元素。
Hashtable:它是一个在集合框架中被识别的遗留类。
Hashtable 是同步的,而 HashMap 不是。另一个区别是 HashMap 中的迭代器是故障安全的,而 Hashtable 的枚举器则不是。如果您在迭代时更改地图,您就会知道。 HashMap 允许其中包含空值,而 Hashtable 不允许。
HashTable 是 jdk 中不应再使用的遗留类。用 ConcurrentHashMap 替换它的用法。如果您不需要线程安全,请使用 HashMap,它不是 threadsafe,但速度更快且使用更少的内存。
HashMap 和 HashTable
关于 HashMap 和 HashTable 的一些要点。请阅读以下详细信息。
1) Hashtable 和 Hashmap 实现 java.util.Map 接口 2) Hashmap 和 Hashtable 都是基于散列的集合。并致力于散列。所以这些是HashMap和HashTable的相似之处。
HashMap 和 HashTable 有什么区别?
1)第一个区别是 HashMap 不是线程安全的,而 HashTable 是 ThreadSafe 2)HashMap 在性能方面更好,因为它不是线程安全的。而 Hashtable 性能并不好,因为它是线程安全的。所以多个线程不能同时访问Hashtable。
HashMap 和 Hashtable 都用于以 key 和 value 的形式存储数据。两者都使用散列技术来存储唯一键。但是下面给出的 HashMap 和 Hashtable 类之间存在许多差异。
https://i.stack.imgur.com/mLpKn.png
Hashtable:
Hashtable 是一种保留键值对值的数据结构。它不允许键和值都为 null。如果添加 null 值,您将获得 NullPointerException
。它是同步的。所以它伴随着它的成本。在特定时间只有一个线程可以访问 HashTable。
例子 :
import java.util.Map;
import java.util.Hashtable;
public class TestClass {
public static void main(String args[ ]) {
Map<Integer,String> states= new Hashtable<Integer,String>();
states.put(1, "INDIA");
states.put(2, "USA");
states.put(3, null); //will throw NullPointerEcxeption at runtime
System.out.println(states.get(1));
System.out.println(states.get(2));
// System.out.println(states.get(3));
}
}
哈希映射:
HashMap 类似于 Hashtable,但它也接受键值对。它允许键和值都为 null。它的性能优于HashTable
,因为它是unsynchronized
。
例子:
import java.util.HashMap;
import java.util.Map;
public class TestClass {
public static void main(String args[ ]) {
Map<Integer,String> states = new HashMap<Integer,String>();
states.put(1, "INDIA");
states.put(2, "USA");
states.put(3, null); // Okay
states.put(null,"UK");
System.out.println(states.get(1));
System.out.println(states.get(2));
System.out.println(states.get(3));
}
}
古老而经典的话题,只想添加这个有用的博客来解释这一点:
http://blog.manishchhabra.com/2012/08/the-5-main-differences-betwen-hashmap-and-hashtable/
Manish Chhabra 的博客
HashMap 和 Hashtable 之间的 5 个主要区别 HashMap 和 Hashtable 都实现了 java.util.Map 接口,但是 Java 开发人员必须了解一些区别才能编写更高效的代码。从 Java 2 平台 v1.2 开始,Hashtable 类被改进为实现 Map 接口,使其成为 Java Collections Framework 的成员。 HashMap 和 Hashtable 之间的主要区别之一是 HashMap 是非同步的,而 Hashtable 是同步的,这意味着 Hashtable 是线程安全的,可以在多个线程之间共享,但 HashMap 不能在没有适当同步的情况下在多个线程之间共享。 Java 5 引入了 ConcurrentHashMap,它是 Hashtable 的替代品,提供了比 Java 中的 Hashtable 更好的可扩展性。同步意味着在一个时间点只有一个线程可以修改一个哈希表。基本上,这意味着任何线程在对哈希表执行更新之前都必须获取对象上的锁,而其他线程将等待锁被释放。 HashMap 类大致相当于 Hashtable,除了它允许空值。 (HashMap 允许空值作为键和值,而 Hashtable 不允许空值)。 HashMap 与 Hashtable 之间的第三个重要区别是 HashMap 中的 Iterator 是一个快速失败的迭代器,而 Hashtable 的枚举器不是,并且如果任何其他线程通过添加或删除除 Iterator 自己的 remove( ) 方法。但这不是保证行为,JVM 会尽最大努力来完成。这也是 Java 中 Enumeration 和 Iterator 的一个重要区别。 Hashtable 和 HashMap 之间更显着的区别是,由于线程安全和同步,如果在单线程环境中使用,Hashtable 比 HashMap 慢得多。因此,如果您不需要同步并且 HashMap 仅由一个线程使用,它会在 Java 中执行 Hashtable。 HashMap 不保证地图的顺序会随着时间的推移保持不变。注意 HashMap 可以通过 Map m = Collections.synchronizedMap(hashMap); 来同步。总而言之,Java 中的 Hashtable 和 HashMap 之间存在显着差异,例如线程安全和速度,基于此,如果您绝对需要线程安全,则仅使用 Hashtable,如果您正在运行 Java 5,请考虑在 Java 中使用 ConcurrentHashMap。
同步或线程安全:
Hash Map 不是同步的,因此它不是线程安全的,并且如果没有适当的同步块,它就不能在多个线程之间共享,而 Hashtable 是同步的,因此它是线程安全的。
空键和空值:
HashMap 允许一个空键和任意数量的空值。Hashtable 不允许空键或空值。
迭代值:
HashMap 中的迭代器是一个快速失败的迭代器,而 Hashtable 的枚举器不是,如果任何其他线程通过添加或删除除 Iterator 自己的 remove() 方法之外的任何元素在结构上修改映射,则抛出 ConcurrentModificationException。
超类和遗产:
HashMap 是 AbstractMap 类的子类,而 Hashtable 是 Dictionary 类的子类。
表现 :
由于 HashMap 不同步,因此它比 Hashtable 更快。
有关 Java 集合的示例、面试问题和测验,请参阅 http://modernpathshala.com/Article/1020/difference-between-hashmap-and-hashtable-in-java
Collections.synchronizedMap()
。Hashtable
中对线程安全的幼稚方法(“同步每个方法应该解决任何并发问题!”)使得线程应用程序非常更糟糕。您最好在外部同步HashMap
(并考虑后果),或使用ConcurrentMap
实现(并利用其扩展 API 实现并发)。底线:使用Hashtable
的唯一原因是旧版 API(约 1996 年)需要它时。