Java 中的 HashMap 和 Hashtable 有什么区别?

What are the differences between a HashMap and a Hashtable in Java?

提问人:dmanxiii 提问时间:9/3/2008 最后编辑:Steve Chambersdmanxiii 更新时间:10/1/2023 访问量:1733979

问:

Java 中的 HashMapHashtable 有什么区别?

对于非线程应用程序,哪个更有效?

Java 集合 希映射 哈希表

评论

43赞 MissFiona 4/10/2017
HashTable 在 Java 1.7 中已过时,建议使用 ConcurrentMap 实现
9赞 Basil Bourque 12/29/2019
@MissFiona 不,这里不需要 ConcurrentMap,因为问题说的是“非线程应用程序”,这意味着线程/并发不是问题。
8赞 alife 2/28/2022
@BasilBourque,是的,但我相信 MissFiona 的意思类似于传统上选择 HashTable 只是因为它的部分线程保护。但 ConcurrentHashMap 已经避免了这一点,因此它通常被视为已停用。通常建议在 HashMap 或 ConcurrentHashMap 之间进行选择。我相信这是一个明智的评论,如果这是她的意思的话。
1赞 aventurin 6/30/2022
根据 doi.org/10.48550/arXiv.1602.00984,Hashtable 在能耗和执行时间方面都比 HashMap 更有效。
0赞 Mark Rotteveel 5/13/2023
@aventurin我想知道现在是否仍然如此,自 Java 15 以来,偏向锁定被禁用。

答:

34赞 pkaeding 9/3/2008 #1

根据这里的信息,我建议使用 HashMap。我认为最大的优点是 Java 会阻止你在迭代它时修改它,除非你通过迭代器来修改它。

评论

1赞 pkaeding 1/1/2011
我很确定它会在修改基础集合之前抛出 ConncurrentModificationException,尽管我可能是错的。
0赞 cHao 4/18/2011
它将尝试检测并发修改并引发异常。但是,如果你对线程做任何事情,它就不能做出任何承诺。绝对任何事情都可能发生,包括破损
54赞 izb 9/3/2008 #2

Hashtable是同步的,而不是。这使得比 .HashMapHashtableHashmap

对于单线程应用程序,请使用,因为它们在功能方面是相同的。HashMap

59赞 Miles D 9/3/2008 #3

Hashtable类似于 和 具有类似的接口。建议使用 ,除非您需要支持旧版应用程序或需要同步,因为这些方法是同步的。因此,就您而言,由于您不是多线程,因此是您最好的选择。HashMapHashMapHashtablesHashMaps

76赞 matt b 9/3/2008 #4

除了 izb 所说的之外,还允许 null 值,而 不允许。HashMapHashtable

另请注意,扩展类,作为 Javadocs 状态,该类已过时,已被接口替换。HashtableDictionaryMap

21赞 Tim Howland 9/3/2008 #5

对于线程应用,通常可以使用 ConcurrentHashMap,具体取决于性能要求。

4223赞 Josh Brown 9/3/2008 #6

Java 中的 HashMapHashtable 之间有几个区别:

  1. Hashtable同步的,而不是。这更适合非线程应用程序,因为未同步的对象通常比同步的对象性能更好。HashMapHashMap

  2. Hashtable不允许键或值。 允许一个键和任意数量的值。nullHashMapnullnull

  3. HashMap 的一个子类是 LinkedHashMap,因此,如果您想要可预测的迭代顺序(默认情况下是插入顺序),您可以轻松地将 .如果您使用 .HashMapLinkedHashMapHashtable

由于同步对您来说不是问题,因此我建议 .如果同步成为一个问题,您还可以查看 ConcurrentHashMapHashMap

评论

133赞 Rok Strniša 11/23/2011
如果要使 HashMap 线程安全,请使用 .Collections.synchronizedMap()
347赞 erickson 3/17/2012
我还想评论一下,线程安全的幼稚方法(“同步每个方法都应该解决任何并发问题!”)使线程应用程序的情况变得更糟。你最好在外部同步一个(并考虑后果),或者使用一个实现(并利用其扩展的API进行并发)。一句话:使用的唯一原因是当遗留 API(大约 1996 年)需要它时。HashtableHashMapConcurrentMapHashtable
8赞 Gaurava Agarwal 6/27/2016
HashMap 使程序员在实际使用它时可以灵活地编写 threadSafe 代码。我很少需要像 ConcurrentHashMap 或 HashTable 这样的线程安全集合。我需要的是同步块中的某些函数集或某些语句,以便线程安全。
7赞 Maneesh Srivastava 3/30/2018
Hashtable 已过时,我们正在将 HashMap 用于非线程安全环境。如果你需要线程安全,那么你可以使用 Collections.synchronizedMap() 或使用 ConcurrentHashMap,它比哈希表更有效。
5赞 Jilles van Gurp 5/19/2018
它已经过时但未弃用,我想知道为什么会这样。我猜删除这个类(以及出于相同原因的 Vector)会破坏太多现有代码,并且用 @Deprecated 注释意味着要删除代码,这显然不存在。
155赞 Apocalisp 9/3/2008 #7

HashMap:使用哈希代码为数组编制索引的接口的实现。: 嗨,1998 年打来的电话。他们希望恢复其集合 API。MapHashtable

不过说真的,你最好完全远离。对于单线程应用,不需要额外的同步开销。对于高度并发的应用,偏执同步可能会导致饥饿、死锁或不必要的垃圾回收暂停。正如 Tim Howland 指出的那样,您可以改用。HashtableConcurrentHashMap

评论

0赞 prap19 11/19/2011
这实际上是有道理的。ConcurrentHashMaps为您提供了同步的自由,调试也变得更加容易。
792赞 serg10 9/3/2008 #8

请注意,很多答案都指出 Hashtable 是同步的。在实践中,这给你带来的很少。同步在访问器/赋值器方法上将停止两个线程同时在映射中添加或删除,但在现实世界中,您通常需要额外的同步。

一个非常常见的成语是“检查然后放置”——即在 中查找一个条目,如果它不存在,则添加它。这绝不是原子操作,无论您使用 或 .MapHashtableHashMap

等效同步可以通过以下方式获得:HashMap

Collections.synchronizedMap(myMap);

但是要正确实现此逻辑,您需要对表单进行额外的同步

synchronized(myMap) {
    if (!myMap.containsKey("tomato"))
        myMap.put("tomato", "red");
}

即使遍历 a 的条目(或由 获取的条目)也不是线程安全的,除非您还防止通过额外的同步进行修改。HashtableHashMapCollections.synchronizedMapMap

ConcurrentMap 接口的实现(例如 ConcurrentHashMap)通过包含线程安全的 check-then-act 语义来解决其中的一些问题,例如:

ConcurrentMap.putIfAbsent(key, value);

评论

63赞 Chris K 4/23/2009
另请注意,如果修改了 HashMap,则指向它的迭代器将无效。
3赞 telebog 11/12/2011
那么synchronized(myMap) {...} 和 ConcurrentHashMap 在线程安全方面有什么区别吗?
0赞 Hot Licks 8/20/2014
在JVM开发团队中工作了很多年,我可以说,Hashtable的内部同步至少对于在客户编写狡猾的并发代码时正确地将矛头指向客户的代码是有用的。我们收到了一些关于 HashMap 内部失败的投诉(因此“显然”是 JDK/JVM 错误),当时原因是并发修改。
0赞 A248 1/8/2021
Collections.synchronizedMap 的实现包含同步的 putIfAbsent,因此您无需自行使用 containsKey/put。
430赞 aberrant80 6/25/2009 #9

Hashtable被视为遗留代码。没有什么是不能使用或派生的,所以对于新代码,我看不出有任何理由回到 。HashtableHashMapHashMapHashtable

评论

111赞 Kip 1/20/2010
来自 Hashtable javadoc(强调后加):“从 Java 2 平台 v1.2 开始,这个类被改造为实现 Map 接口,使其成为 Java 集合框架的成员。但是,您说得对,它是遗留代码。使用 Collections.synchronizedMap(HashMap) 可以更有效地获得同步的所有好处。(类似于 Vector 是 Collections.synchronizedList(ArrayList) 的旧版本。
17赞 pwes 1/12/2012
@aberrant80:不幸的是,在为J2ME编程时,您别无选择,必须使用Hashtable...
0赞 MastAvalons 6/17/2019
同意“哈希表被视为遗留代码”。如果需要并发,则应改用 ConcurentHashMap。
43赞 Neerja 9/8/2011 #10

和之间的另一个关键区别是,HashMap 中的迭代器是快速失败的,而 Hashtable 的枚举器不是,如果任何其他线程通过添加或删除除迭代器自己的 remove() 方法之外的任何元素在结构上修改映射,则抛出 ConcurrentModificationException。但这不是一个有保证的行为,JVM将尽最大努力完成。HashtableHashMap

我的消息来源:http://javarevisited.blogspot.com/2010/10/difference-between-hashmap-and.html

231赞 sravan 10/4/2011 #11

这个问题经常在面试中被问到,以检查候选人是否理解集合类的正确用法,并了解可用的替代解决方案。

  1. 该类大致等同于 ,只是它是非同步的,并且允许 null。(允许 null 值作为键和值,而不允许 s)。HashMapHashtableHashMapHashtablenull
  2. HashMap不保证地图的顺序随时间推移保持不变。
  3. HashMap是非同步的,而是同步的。Hashtable
  4. 中的迭代器是故障安全的,而 的枚举器不是,如果任何其他线程通过添加或删除除自己的方法之外的任何元素在结构上修改映射,则抛出。但这不是一个有保证的行为,JVM将尽最大努力完成。HashMapHashtableConcurrentModificationExceptionIteratorremove()

关于一些重要术语的说明:

  1. 同步意味着在一个时间点只有一个线程可以修改哈希表。基本上,这意味着在对对象执行更新之前,任何线程都必须获取对象的锁,而其他线程将等待锁被释放。Hashtable
  2. 故障安全与迭代器的上下文相关。如果在集合对象上创建了迭代器,并且其他线程尝试“结构化”修改集合对象,则将引发并发修改异常。不过,其他线程也可以调用该方法,因为它不会“结构化地”修改集合。但是,如果在调用之前,集合在结构上已经修改过,则会抛出。setsetIllegalArgumentException
  3. 结构修改是指删除或插入可以有效改变地图结构的元素。

HashMap可以通过以下方式进行同步

Map m = Collections.synchronizeMap(hashMap);

Map 提供 Collection 视图,而不是直接支持通过 Enumeration 对象进行迭代。集合视图极大地增强了界面的表现力,如本节后面所述。Map 允许您遍历键、值或键值对; 不提供第三种选择。Map 提供了一种在迭代过程中删除条目的安全方法; 冇。最后,Map 修复了界面中的一个小缺陷。 有一个名为 contains 的方法,如果包含给定值,则返回 true。给定其名称,如果包含给定的键,则此方法将返回 true,因为该键是 .Map 接口通过重命名方法 来消除这种混淆的根源。此外,这提高了接口的一致性 — parallels .HashtableHashtableHashtableHashtableHashtableHashtableHashtablecontainsValuecontainsValuecontainsKey

地图界面

评论

67赞 Stephen C 9/9/2013
1) HashMap的迭代器不是故障安全的。它们故障快。这两个术语在含义上存在巨大差异。2) 没有对 .3) 如果之前有更改,则操作不会抛出。4) 如果更改映射,也会发生快速故障行为。5) 保证快速失效性能。(不能保证的是,如果您进行并发修改,则 的行为。实际行为是......不可预测。setHashMapput(...)IllegalArgumentExceptionHashMapHashTable
31赞 Stephen C 9/9/2013
6) 也不保证地图元素的顺序会随时间推移而稳定。(您可能与 .HashtableHashtableLinkedHashMap
5赞 5/5/2015
还有人真的担心现在的学生会错误地认为,以某种方式获得集合的“同步版本”意味着您不必在外部同步复合操作?我最喜欢的例子是,它经常让新手感到惊讶,因为完全没有受到保护,特别是如果 和 是同步方法。他们中的许多人都在期待魔法。thing.set(thing.get() + 1);get()set()
2赞 Stefan Reich 2/5/2022
回复 4:ConcurrentModificationException 与线程无关。这是关于保留一个迭代器并修改可能在同一线程中发生的原始集合。
42赞 pwes 1/12/2012 #12

除了这里已经提到的所有其他重要方面之外,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 中,我们还承诺能够像使用旧的脚本语言一样构建和访问 HashMaps:

Map<String,Integer> map = { "orange" : 12, "apples" : 15 };
map["apples"];

更新:不,他们不会登陆 1.8......:(

Project Coin 的集合增强功能会在 JDK8 中吗?

评论

1赞 Paŭlo Ebermann 10/31/2021
“新方式”也适用于 Hashtable(因为它也实现了 map 接口)。
0赞 pwes 11/3/2021
准确地说,既不实现也不实现(这是“new”foreach 语法所必需的)。但是,返回确实允许该语法。HashtableMapIterableHashtable.keySet()Set
0赞 pwes 11/3/2021
更新:嗯,它确实实现了......很高兴在无知这么多年后得到纠正Map
35赞 alain.janinm 4/29/2012 #13
  • HashTable 是同步的,如果你在单个线程中使用它,你可以使用 HashMap,这是一个不同步的版本。不同步对象的性能通常更高一些。顺便说一句,如果多个线程同时访问一个 HashMap,并且至少有一个线程在结构上修改了 map,则必须在外部同步。 Youn 可以使用以下命令将未同步的地图包装在同步的地图中:

    Map m = Collections.synchronizedMap(new HashMap(...));
    
  • HashTable 只能包含非 null 对象作为键或值。HashMap 可以包含一个 null 键和 null 值。

  • Map 返回的迭代器是快速失败的,如果在创建迭代器后的任何时候对 Map 进行结构修改,除了通过迭代器自己的 remove 方法之外,迭代器将抛出一个 .因此,在面对并发修改时,迭代器会快速而干净地失败,而不是冒着在未来不确定时间出现任意、非确定性行为的风险。 Hashtable 的键和元素方法返回的枚举不是快速失败的。ConcurrentModificationException

  • HashTable 和 HashMap 是 Java 集合框架的成员(从 Java 2 平台 v1.2 开始,HashTable 被改造为实现 Map 接口)。

  • HashTable 被认为是遗留代码,如果需要线程安全的高并发实现,文档建议使用 ConcurrentHashMap 代替 Hashtable

  • HashMap 不保证返回元素的顺序。对于 HashTable,我想它是一样的,但我不完全确定,我没有找到明确说明这一点的资源。

3赞 user1506047 8/9/2012 #14

HashMaps为您提供了同步的自由,调试变得更加容易

80赞 Sujan 11/20/2012 #15

请看这张图表。它提供了不同数据结构以及 和 之间的比较。比较准确、清晰、易于理解。HashMapHashtable

Java 集合矩阵

34赞 SkyWalker 12/10/2012 #16

HashMap并且还具有显着的算法差异。以前没有人提到过这一点,所以这就是我提出它的原因。 将构造一个幂为两个大小的哈希表,动态增加它,使得任何存储桶中最多有大约八个元素(碰撞),并且对于一般元素类型,这些元素会很好地搅拌元素。但是,如果您知道自己在做什么,则该实现可以更好、更精细地控制哈希,即您可以使用最接近您的值域大小的素数来修复表大小,这将导致比 HashMap 更好的性能,即在某些情况下更少的冲突。HashtableHashMapHashtable

除了这个问题中广泛讨论的明显差异之外,我认为 Hashtable 是一辆“手动驾驶”汽车,您可以在其中更好地控制哈希,而 HashMap 是“自动驾驶”对应物,通常性能良好。

13赞 raja 1/22/2013 #17
  1. Hashtable是同步的,而不是。HashMap
  2. 另一个区别是迭代器是故障安全的 而 IS 的枚举器则不是。如果更改地图 在迭代时,您就会知道。HashMapHashtable
  3. HashMap允许其中的 null 值,而不允许。Hashtable

评论

4赞 Pankaj 1/29/2013
HashMap 迭代器是快速故障的,而不是故障安全的。这就是为什么我们有 ConcurrentHashMap,它允许在迭代时进行修改。查看这篇文章 journaldev.com/122/...
14赞 Ankit 1/31/2013 #18

HashMap:它是 java.util 包中可用的类,用于以键和值格式存储元素。

哈希表:它是一个遗留类,在集合框架中被识别。

13赞 jontejj 4/15/2013 #19

HashTable 是 jdk 中的一个遗留类,不应再使用。将其用法替换为 ConcurrentHashMap。如果不需要线程安全,请使用 HashMap,它不是线程安全的,但速度更快,使用更少的内存。

评论

1赞 jontejj 8/7/2015
因为当时我认为其他答案并没有否定 HashTable,而是解释说它是线程安全的。事实是,一旦您在代码中看到 HashTable,就应该将其替换为 ConcurrentHashMap,而不会跳过任何节拍。如果线程安全不是问题,那么 HashMap 可用于提高性能。
5赞 pong 7/15/2013 #20

HashMap是模拟的,因此可用于 而 不是。GWT client codeHashtable

3赞 Ekanta Swain 7/23/2013 #21

HashMap 是一个用于将元素存储在键和值中的类 format.it 它不是线程安全的。 因为它没有同步 .where as Hashtable 是同步的。Hashmap 允许 null,但 hastable 不允许 null。

17赞 user1923551 12/11/2013 #22

HashTable 和 HashMaps 有 5 个基本区别。

  1. Maps 允许您迭代和检索键、值和两个键值对,而 HashTable 不具备所有这些功能。
  2. 在 Hashtable 中有一个函数 contains(),使用起来非常混乱。因为包含的含义略有偏差。它是否意味着包含键或包含值?很难理解。同样,在 Maps 中,我们有 ContainsKey() 和 ContainsValue() 函数,它们非常容易理解。
  3. 在哈希图中,您可以在迭代时安全地删除元素。因为在哈希表中是不可能的。
  4. 默认情况下,HashTables 是同步的,因此它可以很容易地与多个线程一起使用。其中,由于 HashMap 默认不同步,因此只能与单个线程一起使用。但是您仍然可以使用 Collections util 类的 synchronizedMap(Map m) 函数将 HashMap 转换为同步。
  5. HashTable 不允许 null 键或 null 值。其中 as HashMap 允许一个 null 键和多个 null 值。
7赞 PetarMI 3/7/2014 #23

由于 Java 中的 Hashtable 是 Dictionary 类的子类,由于 Map Interface 的存在,它现在已经过时了,因此不再使用。此外,对于实现 Map Interface 的类,没有什么是不能用 Hashtable 做的。

14赞 Shreyos Adikari 3/19/2014 #24

我的小贡献:

  1. 和之间的第一个也是最显着的区别是,它不是线程安全的,而是一个线程安全的集合。HashtableHashMapHashMapHashtable

  2. 和之间的第二个重要区别是性能,因为不同步,它的性能比 好。HashtableHashMapHashMapHashtable

  3. vs 的第三个区别是它是过时的类,您应该在 Java 中使用 代替。HashtableHashMapHashtableConcurrentHashMapHashtable

151赞 pierrotlefou 3/25/2014 #25

请记住,在引入 Java 集合框架 (JCF) 之前,它是遗留类,后来经过改造以实现该接口。所以是和.HashTableMapVectorStack

因此,在新代码中始终远离它们,因为正如其他人指出的那样,JCF 中总是有更好的替代方案

这是 Java 集合备忘单,您会发现它很有用。请注意,灰色块包含旧类 HashTable、Vector 和 Stack。

enter image description here

12赞 JegsVala 7/5/2014 #26

HashMap 和 HashTable

  • 关于 HashMap 和 HashTable 的一些要点。 请阅读以下详细信息。

1) Hashtable 和 Hashmap 实现 java.util.Map 接口 2) Hashmap 和 Hashtable 都是基于哈希的集合。并致力于散列。 所以这些是 HashMap 和 HashTable 的相似之处。

  • HashMap 和 HashTable 有什么区别?

1) 第一个区别是 HashMap 不是线程安全的,而 HashTable 是线程安全的 2) HashMap 在性能方面更好,因为它不是线程安全的
。而 Hashtable 的性能并不好,因为它是线程安全的。所以多个线程不能同时访问 Hashtable。

评论

2赞 Ioannis Sermetziadis 10/25/2017
投了反对票,因为这个答案在某些方面是不正确的。Hashtable 不实现 Map 接口,而只扩展了 Dictionary 类,该类已过时。
0赞 Paŭlo Ebermann 10/31/2021
@IoannisSermetziadis至少在 Java 6 API 中,Hashtable 还实现了 Map 接口。
7赞 Night0 8/17/2014 #27

古老而经典的话题,只想添加这个有用的博客来解释这一点:

http://blog.manishchhabra.com/2012/08/the-5-main-differences-between-hashmap-and-hashtable/

Manish Chhabra 的博客

HashMap 和 Hashtable 之间的 5 个主要区别

HashMap 和 Hashtable 都实现了 java.util.Map 接口,但 是 Java 开发人员必须了解才能编写的一些差异 更高效的代码。从 Java 2 平台 v1.2 开始,Hashtable 类 被改造为实现 Map 接口,使其成为 Java 集合框架。

  1. HashMap 和 Hashtable 之间的主要区别之一是 HashMap 是非同步的,而 Hashtable 是同步的,这 意味着哈希表是线程安全的,可以在多个之间共享 线程,但 HashMap 不能在没有 正确的同步。Java 5 引入了 ConcurrentHashMap,它是 Hashtable 的替代方案,并提供比 Java.Synchronized 中的 Hashtable 意味着只有一个线程可以修改哈希 表。基本上,这意味着任何线程之前 在哈希表上执行更新必须获取 对象,而其他人将等待锁定被释放。

  2. HashMap 类大致等同于 Hashtable,只不过它允许 null。(HashMap 允许 null 值作为键和值,而 Hashtable 不允许 null)。

  3. HashMap 与 Hashtable 之间的第三个显着区别是 HashMap 中的迭代器是一个快速失败的迭代器,而 Hashtable 的枚举器 is not 和 throw ConcurrentModificationException,如果任何其他线程修改映射 在结构上,通过添加或删除除迭代器自己的元素之外的任何元素 remove() 方法。但这不是一种有保证的行为,并且会 由 JVM 尽最大努力完成。这也是一个重要的区别 在 Java 中的枚举和迭代器之间。

  4. Hashtable 和 HashMap 之间另一个值得注意的区别是,由于线程安全和同步,Hashtable 要慢得多 如果在单线程环境中使用,则比 HashMap 。所以如果你不这样做 需要同步,而 HashMap 仅由一个线程使用,它 在 Java 中执行 Hashtable。

  5. HashMap 不保证地图的顺序会随着时间的推移保持不变。

请注意,HashMap 可以通过以下方式进行同步

Map m = Collections.synchronizedMap(hashMap);

总而言之,Hashtable 和 Java 中的 HashMap,例如线程安全和速度,仅基于此 如果你绝对需要线程安全,如果你正在运行 Java 5 考虑在 Java 中使用 ConcurrentHashMap。

评论

0赞 IgorGanapolsky 3/25/2017
ConcurrentHashMap 不是读取同步的,而 Hashtable 是。因此,如果您有大量读取操作与写入同时发生,如果您关心数据完整性,Hashtable 将为您提供更好的服务。
20赞 Rahul Tripathi 8/27/2014 #28

1. 并且同时存储密钥和值。HashmapHashTable

2.可以将一个密钥存储为。 无法存储 .HashmapnullHashtablenull

3.不同步,但已同步。HashMapHashtable

4.可同步HashMapCollection.SyncronizedMap(map)

Map hashmap = new HashMap();

Map map = Collections.SyncronizedMap(hashmap);
10赞 IntelliJ Amiya 2/10/2015 #29

Hashtable:

Hashtable 是一种保留键值对值的数据结构。它不允许键和值都为 null。如果添加 null 值,则将得到一个。它是同步的。所以它有它的成本。在特定时间,只有一个线程可以访问 HashTableNullPointerException

示例

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。它的性能比 更好,因为它是 。HashTableunsynchronized

例:

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));

    }
}
6赞 amitguptageek 1/6/2016 #30

同步或线程安全

哈希映射不同步,因此它不安全,如果没有适当的同步块,它不能在多个线程之间共享,而哈希表是同步的,因此它是线程安全的。

Null 键和 null 值

HashMap 允许一个 null 键和任意数量的 null 值。哈希表不允许 null 键或值。

迭代值

HashMap 中的迭代器是一个快速失败的迭代器,而 Hashtable 的枚举器不是,如果任何其他线程通过添加或删除除 Iterator 自己的 remove() 方法之外的任何元素在结构上修改映射,则抛出 ConcurrentModificationException。

超类和遗产

HashMap 是 AbstractMap 类的子类,而 Hashtable 是 Dictionary 类的子类。

性能

由于 HashMap 不同步,因此与 Hashtable 相比,它的速度更快。

有关与 Java 集合相关的示例和面试问题和测验,请参阅 http://modernpathshala.com/Article/1020/difference-between-hashmap-and-hashtable-in-java

19赞 Kostas Kryptos 5/4/2016 #31

除了前面提到的差异之外,需要注意的是,从 Java 8 开始,将每个存储桶中使用的 Nodes(链表)动态替换为 TreeNodes(红黑树),因此即使存在高哈希冲突,搜索时最坏的情况是HashMap

O(log(n)) 表示 Vs O(n)。HashMapHashtable

*上述改进尚未应用于,而仅适用于 、 和 。HashtableHashMapLinkedHashMapConcurrentHashMap

仅供参考,目前,

  • TREEIFY_THRESHOLD = 8:如果一个存储桶包含8个以上的节点,则链表将转换为平衡树。
  • UNTREEIFY_THRESHOLD = 6:当存储桶变得太小时(由于删除或调整大小),树将转换回链表。

评论

0赞 Paŭlo Ebermann 10/31/2021
当然,只有当密钥的哈希码实际上不同并且只是落入同一个存储桶时,这棵树才有用,而不是当您实际获得许多具有相同哈希码的密钥时。
118赞 roottraveller 3/6/2017 #32

已经发布了许多好的答案。我补充了一些新观点并总结了一下。

HashMap两者都用于以键和值形式存储数据。两者都使用哈希技术来存储唯一密钥。 但是下面给出的 HashMap 和 Hashtable 类之间存在许多差异。Hashtable

哈希图

  1. HashMap是非同步的。它不是线程安全的,如果没有正确的同步代码,则无法在多个线程之间共享。
  2. HashMap允许一个 null 键和多个 null 值。
  3. HashMap是 JDK 1.2 中引入的新类。
  4. HashMap速度很快。
  5. 我们可以通过调用此代码使 as 同步HashMap
    Map m = Collections.synchronizedMap(HashMap);
  6. HashMap被 Iterator 遍历。
  7. 中的迭代器是快速失败的。HashMap
  8. HashMap继承 AbstractMap 类。

哈希表

  1. Hashtable是同步的。它是线程安全的,可以与许多线程共享。
  2. Hashtable不允许 null 键或值。
  3. Hashtable是旧类。
  4. Hashtable很慢。
  5. Hashtable在内部同步,不能取消同步。
  6. Hashtable由 Enumerator 和 Iterator 遍历。
  7. 中的枚举器不是快速故障的。Hashtable
  8. Hashtable继承 Dictionary 类。

延伸阅读 Java 中的 HashMap 和 Hashtable 有什么区别?

enter image description here

评论

0赞 IgorGanapolsky 3/25/2017
为什么说~“Hashtable 是遗留类”?支持文档在哪里。
0赞 Abdul 7/30/2018
维护 HashMap 的成本高于 TreeMap。因为 HashMap 会创建不必要的额外存储桶。
0赞 thomas.schuerger 2/4/2021
LinkedHashMap 具有条目的双链列表,而不是存储桶的双链表。存储桶可通过数组索引访问,无需链接。
0赞 aventurin 6/30/2022
Pereira 等人在 2016 年进行的一项研究发现,对于大多数方法,Hashtable 比 HashMap 更快,尤其是 containsKey、get、put 和 remove (arXiv:1602.00984)。所以你声称“HashMap很快”和“Hastable很慢”很可能是错误的。
0赞 starriet 7/24/2022
我认为“可以/不能在许多线程之间共享”的表达可能会误导初学者。“不能共享”并不意味着字面上不能共享。也许说“不应该共享”会更好。但我不是以英语为母语的人,所以...... :)
1赞 KIBOU Hassan 4/21/2017 #33

Hashtable 类是同步的,也就是说,它被设计为由处理多个或多线程进程的应用程序使用。在应用程序到进程的经典情况下,同步类的效率较低,因此 Hashmap 类通常更快。 HashTable 类不接受键或值的 Null 值,而 HashMap 类允许单个键为 Null 且尽可能多的 null。

33赞 Yash 1/4/2018 #34

集合(有时称为容器)只是一个将多个元素组合成一个单元的对象。集合用于存储、检索、操作和传达聚合数据。集合框架 W 是用于表示和操作集合的统一体系结构。

JDK1.2 和 Hashtable JDK1.0 都用于表示成对表示的一组对象。每一对都称为对象。条目的集合由 和 的对象引用。集合中的键必须是唯一的或独特的。[因为它们用于检索特定键的映射值。 集合中的值可以重复。HashMap<Key, Value><Key, Value>EntryHashMapHashtable


« 超类、旧版和集合框架成员

Hashtable 是 JDK1.0 中引入的遗留类,它是 Dictionary 类的子类。 从 JDK1.2 开始,Hashtable 被重新设计为实现 Map 接口,使其成为集合框架的成员。HashMap 从 JDK1.2 中引入之初就是 Java Collection Framework 的成员。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 { ... }

« 初始容量和负载系数

容量是 Hashtable 中的存储桶数量,初始容量只是创建 Hashtable 时的容量。请注意,哈希表是打开的:在哈希冲突的情况下,单个存储桶存储多个条目,必须按顺序搜索这些条目。负载因子是衡量哈希表在容量自动增加之前允许的满量。

HashMap 使用默认初始容量 (16) 和默认负载因子 (0.75) 构造一个空的 Hashtable。其中,as Hashtable 构造具有默认初始容量 (11) 和负载因子/填充比 (0.75) 的空 Hashtable。

Hash Map & Hashtable

« 哈希冲突时的结构修改

HashMap,Hashtable,在发生哈希冲突的情况下,它们将映射条目存储在链表中。 Java8 for HashMap 开始,如果哈希桶增长超过某个阈值,则该桶将从条目链表切换到平衡树。将最坏情况下的性能从 O(n) 提高到 O(log n)。在将列表转换为二叉树时,哈希码用作分支变量。如果同一存储桶中有两个不同的哈希码,则一个哈希码被认为更大,位于树的右侧,另一个位于树的左侧。但是,当两个哈希码相等时,HashMap 会假设键是可比的,并比较键以确定方向,以便可以保持某种顺序。使 HashMap 的键具有可比性是一种很好的做法。在添加条目时,如果存储桶大小达到 TREEIFY_THRESHOLD = 8,则将条目链表转换为平衡树,在删除小于 TREEIFY_THRESHOLD 且最多 UNTREEIFY_THRESHOLD = 6 的条目时,会将平衡树重新转换为条目链表。Java 8 SRC堆栈发布

« 集合视图迭代、快速故障和故障安全

    +--------------------+-----------+-------------+
    |                    | Iterator  | Enumeration |
    +--------------------+-----------+-------------+
    | Hashtable          | fail-fast |    safe     |
    +--------------------+-----------+-------------+
    | HashMap            | fail-fast | fail-fast   |
    +--------------------+-----------+-------------+
    | ConcurrentHashMap  |   safe    |   safe      |
    +--------------------+-----------+-------------+

迭代器本质上是一种快速故障。也就是说,如果集合在迭代时被修改,而不是它自己的 remove() 方法,它会抛出 ConcurrentModificationException。其中,枚举本质上是故障安全的。如果在迭代时修改了集合,则不会引发任何异常。

根据 Java API 文档,迭代器始终优先于枚举。

注意:Enumeration 接口的功能由 Iterator 接口复制。此外,Iterator 还添加了可选的删除操作,并且具有较短的方法名称。新实现应考虑优先使用 Iterator 而不是 Enumeration。

Java 5 中引入了 ConcurrentMap 接口: - 一个由哈希表支持的高度并发、高性能的实现。此实现在执行检索时永远不会阻塞,并允许客户端选择更新的并发级别。它旨在作为 的直接替代品 : 除了实现 之外,它还支持所有 特有的“遗留”方法。ConcurrentHashMapConcurrentMapHashtableConcurrentMapHashtable

  • 每个 s 值都是易失性的,从而确保了竞争修改和后续读取的细粒度一致性;每次读取都反映最近完成的更新HashMapEntry

  • 迭代器和枚举是故障安全的 - 反映自创建迭代器/枚举以来某个时间点的状态;这允许同时读取和修改,但代价是一致性降低。它们不会引发 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();
    }
}

« Null 键和 Null 值

HashMap最多允许一个 null 键和任意数量的 null 值。其中 as 甚至不允许单个 null 键和 null 值,如果键或值为 null,则会引发 NullPointerException。Hashtable

« 同步,线程安全

Hashtable在内部同步。因此,在多线程应用程序中使用是非常安全的。其中 as 不是内部同步的。因此,在没有外部同步的情况下在多线程应用程序中使用是不安全的。您可以使用方法进行外部同步。HashtableHashMapHashMapHashMapCollections.synchronizedMap()

« 性能

由于是内部同步的,这使得速度比 .HashtableHashtableHashMap


@See

12赞 Chathuran D 10/30/2019 #35

HashMap 和 Hashtable 都用于以键和值形式存储数据。两者都使用哈希技术来存储唯一密钥。 下面给出的 HashMap 和 Hashtable 类之间存在许多差异。

enter image description here