内部HashSet只使用HashMap,但为什么我们要使用HashSet而不是HashMap ? &g



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是另一种类型的集合——专注于单个对象而不是成对的项目。为了使HashMapHashSet一样工作,我们需要在每个地方提供一些人工的value对象,如

HashMap<MyItem, Object> set;

,然后用set.put(new MyItem(), null)之类的东西代替set.add(new MyItem()),这没有意义,可能会导致严重的问题(当Object的类型被改变时,当你需要序列化等)

此外,内部实现是你不应该关心的——它可以在下一个Java版本中改变(可能不会),并且下面会使用另一种机制。最重要的是Set接口和HashSet正在实现这个

列表、数组列表、映射、哈希映射、集合等之间的区别是什么?

正如@m所指出的。antkowicz,虽然它内部使用HashMap,但不能保证。

另一个主要原因:

  1. 通常在大型项目中,接口是独立于实现定义的。
  2. 如果业务接口需要Set(甚至Collection),它将定义为Set(或Collection)
  3. 接口不关心底层实现(他们假设预期的行为将被维护)
  4. 接口的任何业务具体实现都应该准确地声明方法签名(以重写)
  5. 所以,他们也会使用Set(或Collection)

另外,Set的不同实现使用不同的Map

  1. ConcurrentSkipListSet使用ConcurrentNavigableMap
  2. HashSet使用HashMap

所以,这很难在接口契约中使用。

最新更新