为什么Sun Java中的HashSet实现使用HashMap作为支持?
查看Java6的源代码,为什么Sun Java中的HashSet实现使用HashMap作为支持?,java,hashmap,hashset,Java,Hashmap,Hashset,查看Java6的源代码,HashSet实际上是使用HashMap实现的,在集合的每个条目上使用虚拟对象实例 我认为条目本身的大小浪费了4字节(在32位机器上) 但是,为什么它仍然被使用?除了使代码维护更容易之外,还有什么理由使用它吗?我猜想,对于实际应用程序或重要的基准测试来说,它从来没有出现过重大问题。为什么要把代码复杂化而没有真正的好处 还要注意的是,在许多JVM实现中,对象大小都是四舍五入的,因此实际上可能不会增加大小(本例中我不知道)。另外,HashMap的代码可能会被编译并存储在缓存中
HashSet
实际上是使用HashMap
实现的,在集合的每个条目上使用虚拟对象实例
我认为条目本身的大小浪费了4字节(在32位机器上)
但是,为什么它仍然被使用?除了使代码维护更容易之外,还有什么理由使用它吗?我猜想,对于实际应用程序或重要的基准测试来说,它从来没有出现过重大问题。为什么要把代码复杂化而没有真正的好处
还要注意的是,在许多JVM实现中,对象大小都是四舍五入的,因此实际上可能不会增加大小(本例中我不知道)。另外,
HashMap
的代码可能会被编译并存储在缓存中。在其他条件相同的情况下,更多的代码=>更多的缓存未命中=>更低的性能。是的,你是对的,确实存在少量的浪费。小,因为对于每个条目,它使用相同的对象PRESENT
(声明为final)。因此,惟一的浪费是HashMap中每个条目的值
我认为,大多数情况下,他们采用这种方法是为了可维护性和可重用性。(JCF开发人员会想,反正我们已经测试了HashMap,为什么不重用它呢。)
但是,如果你有大量的收藏,而且你是一个记忆怪胎,那么你可能会选择更好的替代品,如或。我看了你的问题,花了一段时间思考你说的话。下面是我对
HashSet
实现的看法
有必要让虚拟实例知道该值是否存在于集合中
看看add方法
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
Abd,现在让我们来看看PUT返回值
@返回与键关联的上一个值,如果键没有映射,则返回null。(null返回值也可以表示映射以前与null键关联。) 因此,PRESENT
对象仅用于表示集合包含e值。我想你问过为什么不使用null
而不是PRESENT
。但是,由于map.put(key,value)
将始终返回null
,因此您将无法区分该条目以前是否在映射上,并且无法知道该键是否存在
也就是说,您可能会争辩说,他们本可以使用这样的实现
public boolean add(E e) {
if( map.containsKey(e) ) {
return false;
}
map.put(e, null);
return true;
}
我猜他们会浪费4个字节来避免计算哈希代码,因为这可能会很昂贵,因为要将密钥计算两次(如果要添加密钥的话)
如果你问他们为什么使用浪费8字节的
HashMap
(因为Map.Entry
),而不是使用类似的只有4个条目的其他数据结构,那么是的,我会说他们这样做是因为你提到的原因。事实上,这不仅仅是HashSet
。Java 6中Set
接口的所有实现都基于底层Map
。这不是一项要求;这就是实现的方式。您可以查看的各种实现的文档
你的主要问题是
但是,为什么它仍然被使用?有
除了制作它,还有什么理由使用它吗
更容易维护代码
我认为代码维护是一个很大的激励因素。防止重复和膨胀也是如此
Set
和Map
是类似的接口,因为不允许重复元素。(我认为唯一没有地图支持的Set
是CopyOnWriteArraySet
,这是一个不寻常的集合,因为它是不可变的。)
具体而言:
从:
不包含任何内容的集合
重复元素。更正式地说,
集合不包含元素对e1
和e2,使得e1等于(e2),并且
大多数情况下只有一个空元素。正如
它的名字,这个接口模型
数学集合抽象
Set接口会放置额外的
规定,超越继承的规定
从集合界面,在
所有施工人员的合同,以及
加法的契约,等于和
hashCode方法。声明
其他继承的方法也很有用
包括在这里是为了方便。(修订)
随附的规范
声明是根据实际情况量身定制的
设置接口,但它们不包含
任何附加规定。)
附加规定
构造器是,毫不奇怪,
所有构造函数都必须创建一个
不包含重复项的集合
元素(如上所述)
和来自:
将键映射到值的对象。
地图不能包含重复的键;每个键最多可以映射到一个值
如果您可以使用现有代码实现集合
,那么您可以从现有代码中获得的任何好处(例如,速度)也会累积到集合
如果选择在没有映射
支持的情况下实现集
,则必须复制为防止重复元素而设计的代码。啊,有趣的讽刺
也就是说,没有什么可以阻止您以不同的方式实现
集。我的猜测是,HashSet最初是根据HashMap实现的,以便快速、轻松地完成。就代码行而言,HashSet只是HashMap的一小部分
我猜它仍然没有被优化的原因是害怕改变
然而,浪费比你想象的要严重得多。在32位和64位上,HashSet比需要的大4倍,HashMap比需要的大2倍。HashMap可以用一个包含键和值的数组(加上冲突链)来实现。这意味着每个条目有两个指针,或者64位虚拟机上有16个字节。事实上,HashMap每个条目都包含一个条目对象,而