HashSet和HashMap的区别是什么?

214
除了 HashSet 不允许重复值之外,HashMapHashSet 有什么不同?
我是说在实现上有何不同?这有点含糊,因为两者都使用哈希表来存储值。

HashSet是使用HashMap实现的。 - therealprashant
我认为了解HashSet与ArrayList的区别将有助于您理解上述问题的答案:https://dev59.com/ZGMl5IYBdhLWcg3wFThP - djangofan
20个回答

349

HashSet是一个集合,例如{1,2,3,4,5}

HashMap是一个键 -> 值 (key to value) 映射表,例如{a -> 1, b -> 2, c -> 2, d -> 1}

请注意在上面的HashMap示例中,键不能重复,但值可以重复。

而在HashSet中,元素不得重复。


1
但是混淆最有趣的原因是,即使在HashSet中,您也需要一个“键”来访问元素。也就是说,对象即使在数学中也有名称(或地址),如果要访问或引用它们。因此,在这个实际意义上,HashSet是一个特别简单的HashMap,以其元素的名称(或地址)为键。 - Andrew Marshall

185
它们是完全不同的构造。一个HashMapMap的实现。Map将键映射到值。键查找使用哈希进行。
另一方面,HashSetSet的实现。Set旨在匹配集合的数学模型。HashSet确实使用HashMap来支持其实现,正如您所指出的那样。然而,它实现了完全不同的接口。
当您正在寻找最适合您目的的Collection时,这个Tutorial是一个很好的起点。如果您真的想知道发生了什么,there's a book for that也可以。

这个语句有点简单化。在底层,还有一些更多的操作。返回指定对象的哈希值。除了对象本身的hashCode之外,该方法还应用了一个“补充哈希函数”,以防止低质量的哈希函数。这很关键,因为HashMap使用二次幂长度哈希表。然而,如果您查看文档,您会发现此哈希将物品分配到“桶”中,所以最终我认为两件事可能会被映射到同一个桶中。 - justkt
1
回答你的第二个问题 - 不是。如果你想要(key -> value),那么使用Map,正如@Bruno Rothgiesser所定义的那样。如果你想要非重复元素,那么使用Set。如果你想要重复元素而不是key->value,我建议你查看java.util.List实现。请查看Collection教程以获取权威指南:http://java.sun.com/docs/books/tutorial/collections/index.html - justkt
@justk:是的,您可以在一个桶中获取两个键,然后使用equals()来区分它们。这就是为什么hashCode()和equals()兼容性非常重要的原因。 - Michael Borgwardt
6
@SpikETidE说:HashMap和HashSet都不允许重复,这就是它们存在的意义。 - Michael Borgwardt
28
集合没有键值对,只有元素。HashSet 通过使用将集合元素作为键且忽略值的 HashMap 实现。 - Michael Borgwardt

77

哈希集合

  1. HashSet类实现了Set接口。
  2. 在HashSet中,我们存储对象(元素或值)。 例如,如果我们有一个字符串元素的HashSet,它可以表示一个HashSet元素的集合:{"Hello",“Hi”,“Bye”,“Run”}。
  3. HashSet不允许重复的元素,这意味着你不能在HashSet中存储重复的值。
  4. HashSet允许有一个单一的空值。
  5. HashSet未同步,这意味着它们不适合进行线程安全操作,除非显式地同步。[类似]

                      add      contains next     notes
HashSet               O(1)     O(1)     O(h/n)   h is the table 

HashMap

  1. HashMap类实现了Map接口
  2. HashMap用于存储键值对。简而言之,它维护了键和值之间的映射(HashMap类大致相当于Hashtable,但是它是不同步的,并允许null值)。以下是如果HashMap具有整数键和String类型的值时,您可以表示HashMap元素的方式:例如 {1->“Hello”,2->“Hi”,3->“Bye”,4->“Run”}
  3. HashMap不允许重复的键,但允许有重复的值。
  4. HashMap允许单个null键和任意数量的null值。
  5. HashMap未同步,这意味着它们不适合进行线程安全操作,除非显式同步。[相似]

                       get      containsKey next     Notes
 HashMap               O(1)     O(1)        O(h/n)   h is the table 

请参考此文章以获取更多信息。


41

很遗憾,它们的名字都以Hash开头。那只是它们中最不重要的部分。重要的部分在Hash之后 - 也就是其他人指出的SetMap。它们分别是无序集合Set和具有键访问的集合Map。它们恰好是用哈希实现的 - 这就是它们名称的来源 - 但它们的本质隐藏在名称的这一部分之后。

不要被它们的名称所困惑; 它们是非常不同的东西。


@HiteshSahu 它们都使用哈希表(https://en.wikipedia.org/wiki/Hash_table)实现。这是一种很好的数据结构,适合表示集合,在正确的方式下效率高,而且HashMap的键被实现为HashSet。所以,无论谁命名它们都会费一些力气来实现它们,并且注重于实现而不是它们的目的(猜测)。 - Carl Manaster

8

Hashset内部实现了HashMap。如果您查看实现方式,则HashSet中插入的值被存储为HashMap中的键,而该值是Object类的虚拟对象。
HashMap和HashSet之间的区别如下:

  1. HashMap包含键值对,每个值都可以通过键访问,而HashSet需要每次迭代,因为没有获取方法。
  2. HashMap实现Map接口,允许一个空值作为键和多个空值作为值,而HashSet实现Set接口,仅允许一个空值和无重复值。(请记住HashMap键中允许一个空键,因此HashSet中允许一个空值,因为HashSet在内部实现了HashMap)。
  3. HashSetHashMap在迭代时不维护插入顺序。

5

HashSet允许我们将对象存储在集合中,而HashMap允许我们根据键和值存储对象。每个对象或存储的对象都将具有键。


5

如它们的名称所示,HashMap是一个关联的Map(从键到值的映射),HashSet则只是一个Set


3
@SpikETidE提到的是关于如何实现HashSet中元素唯一性的细节,但是HashSet的含义是实现一个集合。 - Michael Borgwardt
1
所以总的来说,“如果你不想要重复项,请使用 HashSet……如果你不关心重复项,请使用 HashMap”是正确的吗? - SpikETidE
3
Java没有为“可能包含重复元素的集合”(即“袋子”)实现一个特定的类,您可以使用List来实现(尽管List为该“袋子”添加了一些语义:顺序;但您可以忽略这一点)。 - leonbloy

2

Java中HashSet和HashMap的区别

1) HashMap和HashSet最显著的区别是,HashMap是Map接口的实现,而HashSet是Set接口的实现。这意味着HashMap是基于键值对的数据结构,而HashSet通过不允许重复保证唯一性。实际上,在Java中,HashSet是HashMap的包装器。如果您查看HashSet.java中的add(E e)方法代码,您将看到以下代码:

public boolean add(E e) 
{
    return map.put(e, PRESENT)==null;
}

它将对象作为键放入映射中,值是一个虚拟的 final 对象 PRESENT。

2) HashMap 和 HashSet 的第二个区别是,在 Java 中我们使用 add() 方法将元素放入 Set 中,但是我们使用 put() 方法将键和值插入到 HashMap 中。

3) HashSet 只允许一个空键,但是 HashMap 可以允许一个空键和多个空值。

这就是 Java 中 HashSet 和 HashMap 之间的区别。总结一下,HashSet 和 HashMap 是两种不同类型的集合,一个是 Set,另一个是 Map。


2
一个HashMap是用于添加、获取、删除等操作的对象,这些对象由任何类型的自定义键索引。
一个HashSet是用于添加元素、删除元素和通过比较它们的哈希值来检查元素是否存在的集合。
因此,HashMap包含元素,而HashSet则记住它们的哈希值。

2
通过比较它们的哈希值并调用它们的 equals() 方法。 - user207421

2

HashSet和HashMap在Java中的区别

HashSet内部使用HashMap来存储对象。当调用add(String)方法时,它会调用HashMap的put(key,value)方法,其中key=String对象,value=new Object(Dummy)。因此,它维护了没有重复对象,因为键就是值对象。

在Hashset/HashMap中存储为键的对象应该覆盖hashCode和equals协议。

用于访问/存储HashMap中值对象的键应该声明为final,因为当其被修改时,无法定位值对象并返回null。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接