目录
简介
字段 map,PRESENT
构造函数5个
查询 iterator,size,isEmpty,contains
操作 add,remove,clear
clone,readObject,writeObject
spliterator
/**
* 这个类实现Set接口,由一个散列表(实际上是一个HashMap实例)支持。
* 它不保证集合的迭代顺序;特别是,它不能保证顺序保持不变。该类允许null元素。
*
* 这个类为基本操作(add,remove,contains,size)提供了常数时间性能,假设散列函数正确地将元素分散到各个桶中。
* 遍历这个集合需要的时间与HashSet实例的大小(元素的数量) 加上 支持HashMap实例的“容量”(桶的数量)的总和成比例。
* 因此,如果迭代性能很重要,那么不要将初始容量设置得太高(或负载因子太低)是非常重要的。
*
*
注意,这个实现不是同步的。如果多个线程同时访问一个散列集,
* 并且至少有一个线程修改该散列集,则必须在外部对其进行同步。
* 这通常是通过对一些自然封装了集合的对象进行同步来实现的。
*
* 如果不存在这样的对象,则应该使用Collections.synchronizedSet方法来保证它。
* 这最好在创建时完成,以防止意外的不同步的访问set的行为:
*
*
* Set s = Collections.synchronizedSet(new HashSet(...));
*
* 这个类的迭代器方法返回的迭代器是快速失效的:如果在迭代器创建后的任何时候修改集合,
* 除了通过迭代器自己的删除方法之外,任何方式都可以,迭代器抛出ConcurrentModificationException。
* 因此,在面对并发修改时,迭代器会快速而干净地失败,而不是在将来某个不确定的时间冒任意的、不确定的行为的风险。
*
*
注意,不能保证迭代器的快速故障行为,因为通常来说,在存在非同步并发修改的情况下,不可能做出任何严格的保证。
* 故障快速迭代器在最大努力的基础上抛出ConcurrentModificationException。
* 因此,编写一个依赖于这个异常的正确性的程序是错误的:迭代器的快速故障行为应该只用于检测bug。
*
* @param the type of elements maintained by this set
*
* @author Josh Bloch
* @author Neal Gafter
* @see Collection
* @see Set
* @see TreeSet
* @see HashMap
* @since 1.2
*/
public class HashSet
extends AbstractSet
implements Set, Cloneable, java.io.Serializable
// 内置了一个map
private transient HashMap map;
// map.put(e, PRESENT) 作为map里的value
// PRESENT是static final的常量,所有hashset共享
private static final Object PRESENT = new Object();
/**
* 创建一个新的,空的set,依赖的HashMap实例是默认的,初始容量为16,初始负载因子为0.75
*/
public HashSet() {
map = new HashMap<>();
}
/**
* 构造一个新集合,该集合包含指定集合中的元素。
* HashMap是使用默认的负载因子(0.75)和足够容纳指定集合中的元素的初始容量创建的。
*
* @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) {
// c的size/0.75 +1 为容量 ,最小为16
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
/**
* 构造一个新的空集;支持的HashMap实例具有指定的初始容量和指定的负载因子。
*
* @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);
}
/**
* 构造一个新的空集;支持的HashMap实例具有指定的初始容量和缺省负载因子(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);
}
/**
* 构造一个新的空的链接哈希集(这个包的私有构造函数只被LinkedHashSet使用)。
* 支持的HashMap实例是一个LinkedHashMap,它具有指定的初始容量和指定的负载因子。
*
* @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) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
/**
* 在这个集合的元素上返回一个迭代器。元素没有按照特定的顺序返回。
*
* @return an Iterator over the elements in this set
* @see ConcurrentModificationException
*/
public Iterator iterator() {
// 返回map的keySet视图的迭代器
return map.keySet().iterator();
}
/**
* 返回此集合中的元素
*
* @return the number of elements in this set (its cardinality)
*/
public int size() {
return map.size();
}
/**
* 如果该集合不包含元素,则返回true。
*
* @return true if this set contains no elements
*/
public boolean isEmpty() {
return map.isEmpty();
}
/**
* 如果set包含指定元素,返回true。
* 更正式地,当且仅当集合至少有一个这样的元素时,返回true。
* (o==null ? e==null : o.equals(e)).
*
* @param o element whose presence in this set is to be tested
* @return true if this set contains the specified element
*/
public boolean contains(Object o) {
// map是否有这个key
return map.containsKey(o);
}
/**
* 如果set没有指定元素,将指定元素加入set。
* 更正式地说,如果set不包含元素e2,有指定元素e,
* (e==null ? e2==null : e.equals(e2))
* 将e加入到set。
*
*
如果set已经包含了这个元素,调用让set不改变,并且返回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) {
// key为e,value为一个常量 new Object()
return map.put(e, PRESENT)==null;
}
/**
* 如果指定元素存在,从set中移除指定元素(可选的操作)。
* 更正式地说,如果set包含一个这样的元素,就移除一个这样的元素 ,
* (o==null ? e==null : o.equals(e))
* 如果集合包含指定元素,返回true。(如果集合因为调用而改变,返回true)
* (调用结束后,set不会包含这个元素)
*
* @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) {
// map移除key为o
return map.remove(o)==PRESENT;
}
/**
* 移除set中所有的元素
*/
public void clear() {
map.clear();
}
/**
* 返回此HashSet实例的浅拷贝:元素本身没有被克隆。
*
* @return a shallow copy of this set
*/
@SuppressWarnings("unchecked")
public Object clone() {
try {
// 对自己进行浅拷贝
HashSet newSet = (HashSet) super.clone();
// 对map进行浅拷贝
newSet.map = (HashMap) map.clone();
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
/**
* 将这个HashSet实例的状态保存到流中(即序列化它)。
*
* @serialData The capacity of the backing HashMap instance
* (int), and its load factor (float) are emitted, followed by
* the size of the set (the number of elements it contains)
* (int), followed by all of its elements (each an Object) in
* no particular order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// 写出隐藏的字段。
s.defaultWriteObject();
// 写出HashMap的容量和负载因子
s.writeInt(map.capacity());
s.writeFloat(map.loadFactor());
// 写出size
s.writeInt(map.size());
// 以适当的顺序写出所有的元素
for (E e : map.keySet())
s.writeObject(e);
}
/**
* 从流中重新构造HashSet实例(即反序列化它)。
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// 读入隐藏字段
s.defaultReadObject();
// 读入容量,验证非负
int capacity = s.readInt();
if (capacity < 0) {
throw new InvalidObjectException("Illegal capacity: " +
capacity);
}
// 读入负载因子,验证整数和不是NaN
float loadFactor = s.readFloat();
if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
throw new InvalidObjectException("Illegal load factor: " +
loadFactor);
}
// 读入size,验证非负
int size = s.readInt();
if (size < 0) {
throw new InvalidObjectException("Illegal size: " +
size);
}
// 根据size和负载因子,设置容量,保证HashMap至少是25%是满的,但是小于最大容量
capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),
HashMap.MAXIMUM_CAPACITY);
// 创建支持的HashMap,安装上面得到的capacity和loadFactor
// 根据自己是HashSet还是LinkedHashSet,创建HashMap,LinkedHashMap
map = (((HashSet>)this) instanceof LinkedHashSet ?
new LinkedHashMap(capacity, loadFactor) :
new HashMap(capacity, loadFactor));
// 以适当的顺序读入所有的元素
for (int i=0; i
/**
* 在这个集合的元素上创建一个迟绑定和快速失败的Spliterator。
* Spliterator报告SIZED和DISTINCT。覆盖的实现应该记录额外特征值。
*
* @return a {@code Spliterator} over the elements in this set
* @since 1.8
*/
public Spliterator spliterator() {
// 返回HashMap的keySpliterator
return new HashMap.KeySpliterator(map, 0, -1, 0, 0);
}