为什么HashSet的内部实现会创建一个HashMap来存储它的值?

时间:2018-06-14 10:41:27

标签: java data-structures hashmap hashset

我是编码新人,现在正在学习Java中的HashSet容器。真正让我困惑的是HashSet的内部实现也创建了一个私有的HashMap对象存储它的值和单个对象PRESENT

所以我的问题是:

  • 为什么HashSet结构需要一个HashMap对象来存储它的值?(为什么不使用数组结构或链接结构?)
  • 单例对象PRESENT的用法是什么?(用于确定插入是否成功?)

3 个答案:

答案 0 :(得分:7)

HashSet可以被视为HashMap的私人案例,我们只关心密钥。

使用HashMap实例作为HashSet实现是避免代码重复的一种方法。而不是复制HashMap类中的HashSet代码的重要部分(管理存储桶数组的所有代码(包括每个存储桶中的链接列表或树结构)),并找到存储桶匹配一个给定的密钥),JDK开发人员选择重用HashMap代码。

PRESENT实例是一个虚拟实例,用作HashMap的后备HashSet中的值。它用于避免分配多个虚拟值。

这是评论中的状态:

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

答案 1 :(得分:2)

  

为什么HashSet结构需要HashMap个对象来存储它的值? (为什么不使用数组结构或链接结构?)

从技术上讲,它并不需要。

然而,Java团队更容易 1 HashMap / HashSet这样复杂的事情维护单一实现。 (请注意,需要复杂性以使实现能够很好​​地适用于各种用例。)

在实现HashSet作为HashMap的包装器时,每个条目的内存开销为1。然而,这足够小,他们"认为这是可以接受的。如果对您不可接受那么您可以自由地实施和维护自己的HashSet 2 的改进版本。

  

单例对象PRESENT的用法是什么?

PRESENT实例是一个实现细节。它是用作包装HashMap实例中的值的虚拟值。

  

用于确定插入是否成功?

部分是,是的。

1 - 最近发现HashSet / HashMap进行了重大改革以提高性能......但是Java团队并没有把这个机会分开实施

2 - 你不会成为第一个这样做的人。但是,您可能会发现难以全面提高HashSet性能(即所有用例)......并且仍能正确实施java.util.Map API。将HashMap.Node类value字段分解出来可能是唯一的大赢家。

答案 2 :(得分:1)

HashSet被称为HashSet,因为它使用HashMap来完成其工作。 HashMap是一个非常方便的结构,允许您非常快速地查找与某个键相关的信息,只要该键具有为其定义的良好哈希函数。

平凡地说,如果使用链接列表实现了一个集合,那么它将被称为LinkedListSet而不是HashSet,而且会慢得多。数组同上。

仅使用PRESENT单例,因为HashMap需要存储内容;只要有某些东西存在或不存在,HashSet的目的无关紧要,所以可能总是同样的事情。

Set来到JavaScript和Perl之前,你会经常看到这种模式,其中一个人只需要一个对象(JS)或一个哈希(Perl)并填充一个true或{{ 1}}在其中为每个现在的成员。因此,即使没有专用的1对象,最佳解决方案也基本相同。

在位向量上实现相同的功能会有点内存效率,因为允许的唯一值不存在或存在,但它将涉及更多工作并复制现有功能。但是,找到数组的哪个索引包含哪个键的值的部分是相同的。