HashSet的内部实现.......................................
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
//constructors
public HashSet() {
map = new HashMap<>();
}
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(Collection<? usnoextends E> c) {
map = new HashMap<>(Math.imax((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
//add method
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
}
内部HashSet只使用HashMap,性能方面HashMap比HashSet快那么为什么我们不直接使用HashMap而使用HashSet呢?
因为HashSet
是另一种类型的集合——专注于单个对象而不是成对的项目。为了使HashMap
像HashSet
一样工作,我们需要在每个地方提供一些人工的value
对象,如
HashMap<MyItem, Object> set;
,然后用set.put(new MyItem(), null)
之类的东西代替set.add(new MyItem())
,这没有意义,可能会导致严重的问题(当Object
的类型被改变时,当你需要序列化等)
此外,内部实现是你不应该关心的——它可以在下一个Java版本中改变(可能不会),并且下面会使用另一种机制。最重要的是Set
接口和HashSet
正在实现这个
列表、数组列表、映射、哈希映射、集合等之间的区别是什么?
正如@m所指出的。antkowicz,虽然它内部使用HashMap,但不能保证。
另一个主要原因:
- 通常在大型项目中,接口是独立于实现定义的。
- 如果业务接口需要Set(甚至Collection),它将定义为
Set
(或Collection
) - 接口不关心底层实现(他们假设预期的行为将被维护)
- 接口的任何业务具体实现都应该准确地声明方法签名(以重写) 所以,他们也会使用
Set
(或Collection
)另外,Set
的不同实现使用不同的Map
ConcurrentSkipListSet
使用ConcurrentNavigableMap
HashSet
使用HashMap
所以,这很难在接口契约中使用。