HashSet
是一个不允许存储重复元素的集合,它的实现比较简单,只要理解了 HashMap
,HashSet
就水到渠成了。当然了解HashMap可以参考我的这篇文章
//使用HashMap来实现Set的相关功能
private transient HashMap<E,Object> map;
// 将假value与map中的对象关联
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
/**
* 创建一个空的set,背后是HashMap的实例,初始容量为16,负载因子0.75
* Constructs a new, empty set; the backing HashMap instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
/**
* 根据的指定初始容量,创建set,HashMap
* Constructs a new, empty set; the backing HashMap instance has
* the specified initial capacity and default load factor (0.75).
*
* @param initialCapacity the initial capacity of the hash table
* @throws IllegalArgumentException if the initial capacity is less
* than zero
*/
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
/**
*根据的指定初始容量和负载因子,创建set,HashMap
* Constructs a new, empty set; the backing HashMap instance has
* the specified initial capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hash map
* @param loadFactor the load factor of the hash map
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
/**
* 这个构造方法是被LinkedHashSet所使用,指定初始容量和负载因子
* Constructs a new, empty linked hash set. (This package private
* constructor is only used by LinkedHashSet.) The backing
* HashMap instance is a LinkedHashMap with the specified initial
* capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hash map
* @param loadFactor the load factor of the hash map
* @param dummy(假) ignored (distinguishes this
* constructor from other int, float constructor.)
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
//dummy:用来辨别调用的构造方法
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
/**
* 创建一个新的set集合保存指定集合中的元素,使用默认的负载因子和足够的容量
* Constructs a new set containing the elements in the specified
* collection. The HashMap is created with default load factor
* (0.75) and an initial capacity sufficient to contain the elements in
* the specified collection.
*
* @param c the collection whose elements are to be placed into this set
* @throws NullPointerException if the specified collection is null
*/
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
AbstractCollection#addAll
/**
* {@inheritDoc}
*
* 此实现在指定的集合上迭代,并添加迭代器返回的每个对象到此集合中
* This implementation iterates over the specified collection, and adds
* each object returned by the iterator to this collection, in turn.
*
*
Note that this implementation will throw an
* UnsupportedOperationException unless add is
* overridden (assuming the specified collection is non-empty).
*
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @throws IllegalStateException {@inheritDoc}
*
* @see #add(Object)
*/
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
/**
* 如果指定元素在map中不存在,添加指定的元素。如果存在,返回false
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element e to this set if
* this set contains no element e2 such that
* (e==null ? e2==null : e.equals(e2)).
* If this set already contains the element, the call leaves the set
* unchanged and returns false.
*
* @param e element to be added to this set
* @return true if this set did not already contain the specified
* element
*/
public boolean add(E e) {
//map.put返回以前的值或者null
return map.put(e, PRESENT)==null;
}
比较关键的就是这个 add()
方法。 可以看出它是将存放的对象当做了 HashMap
的健,value
都是相同的 PRESENT
。由于 HashMap
的 key
是不能重复的,所以每当有重复的值写入到 HashSet
时,value
会被覆盖,但 key
不会受到影响,这样就保证了 HashSet
中只能存放不重复的元素
/**
* 如果在set中存在,移除指定的元素。如果存在,返回true,否则返回false
* Removes the specified element from this set if it is present.
* More formally, removes an element e such that
* (o==null ? e==null : o.equals(e)),
* if this set contains such an element. Returns true if
* this set contained the element (or equivalently, if this set
* changed as a result of the call). (This set will not contain the
* element once the call returns.)
*
* @param o object to be removed from this set, if present
* @return true if the set contained the specified element
*/
public boolean remove(Object o) {
//如果存在,返回value为PRESENT,否则返回null
return map.remove(o)==PRESENT;
}
LinkedHashSet继承HashSet,基本的方法是相同的,只是底层的实现换成了LinkedHashMap,实现了顺序的记录。如果想了解LinkedHashMap,可以参考这篇文章