我是编码新人,现在正在学习Java中的HashSet
容器。真正让我困惑的是HashSet
的内部实现也创建了一个私有的HashMap
对象存储它的值和单个对象PRESENT
。
所以我的问题是:
HashSet
结构需要一个HashMap
对象来存储它的值?(为什么不使用数组结构或链接结构?)PRESENT
的用法是什么?(用于确定插入是否成功?)答案 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
对象,最佳解决方案也基本相同。
在位向量上实现相同的功能会有点内存效率,因为允许的唯一值不存在或存在,但它将涉及更多工作并复制现有功能。但是,找到数组的哪个索引包含哪个键的值的部分是相同的。