Set接口除了从Collection接口继承之外,还添加了所有构造函数的约定以及add,equals和hashCode方法的约定。
public interface Set extends Collection {
//返回此集合中的元素数(其基数)。
int size();
//如果此集合不包含元素,则返回true。
boolean isEmpty();
//如果此集合包含指定的元素,则返回true。
boolean contains(Object o);
//返回此集合中元素的迭代器。
Iterator iterator();
//返回一个包含此集合中所有元素的数组。
Object[] toArray();
//返回一个包含此集合中所有元素的数组; 返回的数组的运行时类型是指定数组的运行时类型。
T[] toArray(T[] a);
//将指定的元素添加到此集合(如果尚未存在)(可选操作)。
boolean add(E e);
//如果存在,则从该集合中删除指定的元素(可选操作)。
boolean remove(Object o);
//如果此集合包含指定集合的所有元素,则返回true。
boolean containsAll(Collection> c);
//将指定集合中的所有元素添加到此集合(如果尚未存在)(可选操作)。
boolean addAll(Collection extends E> c);
//仅保留该集合中包含在指定集合中的元素(可选操作)。
boolean retainAll(Collection> c);
//从此集合中删除指定集合中包含的所有元素(可选操作)。
boolean removeAll(Collection> c);
//从此集合中删除所有元素(可选操作)。
void clear();
//将指定的对象与此集合进行比较以实现相等。
boolean equals(Object o);
//返回此集合的哈希码值。
int hashCode();
//在此集合中的元素上创建一个Spliterator。
default Spliterator spliterator() {
return Spliterators.spliterator(this, Spliterator.DISTINCT);
}
}
该类提供了Set接口的骨架实现,以最大限度地减少实现此接口所需的工作量。
通过扩展此类来实现集合的过程与通过扩展AbstractCollection实现集合的过程相同,除了此类的子类中的所有方法和构造函数都必须遵守由Set接口施加的附加约束(例如,添加方法不能允许将一个对象的多个实例添加到集合中)。
请注意,此类没有覆盖AbstractCollection类中的任何实现。它只是为equals和hashCode添加了实现。
public abstract class AbstractSet extends AbstractCollection implements Set {
protected AbstractSet() {
}
//将指定的对象与此set进行比较以实现相等。 如果给定的对象也是一个set,则返回true,两个set的大小相同,给定set的每个成员都包含在该set中。 这确保了equals方法在Set接口的不同实现中正常工作。
//这个实现首先检查指定的对象是否是该set; 如果是,则返回true。 然后,它检查指定的对象是否是与该set的大小相同的set; 如果没有,则返回false。 如果是这样,它返回containsAll((Collection)o)。
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection> c = (Collection>) o;
if (c.size() != size())
return false;
try {
return containsAll(c);
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
}
//返回此set的哈希码值。 set的散列码被定义为set中的元素的哈希码的和,其中空元素的哈希码被定义为零。
//这确保s1.equals(s2)意味着任何两个set 中s1和s2的s1.hashCode()== s2.hashCode(),如Object.hashCode()的一般合同所要求的。
//该实现遍历set,在set中的每个元素上调用hashCode方法,并将结果相加。
public int hashCode() {
int h = 0;
Iterator i = iterator();
while (i.hasNext()) {
E obj = i.next();
if (obj != null)
h += obj.hashCode();
}
return h;
}
//从此set中删除指定set中包含的所有元素(可选操作)。如果指定的collection也是一个set,则该操作有效地修改该set,使得其值是两组的非对称set差异。
//该实现通过调用每个方法的size方法来确定该set和指定collection的哪一个。如果此set具有较少的元素,则该实现将遍历此set,依次检查迭代器返回的每个元素,以查看它是否包含在指定的collection中。如果包含,它将使用迭代器的remove方法从该set中删除。如果指定的collection具有较少的元素,则实现将遍历指定的collection,从该set中删除迭代器返回的每个元素,使用该set的remove方法。
//总之就是将小的set的元素从大的set里面删除
public boolean removeAll(Collection> c) {
Objects.requireNonNull(c);
boolean modified = false;
if (size() > c.size()) {
for (Iterator> i = c.iterator(); i.hasNext(); ) //此处定义i为collection的迭代器
modified |= remove(i.next());
} else {
for (Iterator> i = iterator(); i.hasNext(); ) { //此处定义i为set的迭代器
if (c.contains(i.next())) {
i.remove();
modified = true;
}
}
}
return modified;
}
}
通俗一点将HashSet借了HashMap的壳下了自己的蛋,HashSet将元素作为HashMap的key,然后调用HashMap中的方法进行操作。
public class HashSet extends AbstractSet implements Set, Cloneable, java.io.Serializable
{
static final long serialVersionUID = -5024744406713321676L;
private transient HashMap map;
//与支持map中的对象相关联的虚拟值
private static final Object PRESENT = new Object();
//构造一个新的,空的集合; 支持HashMap实例具有默认初始容量(16)和负载因子(0.75)。
public HashSet() {
map = new HashMap<>();
}
//构造一个包含指定集合中的元素的新集合。
//HashMap以默认负载因子(0.75)创建,初始容量足以包含指定集合中的元素。
public HashSet(Collection extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
//构造一个新的,空的集合; 支持HashMap实例具有指定的初始容量和指定的负载因子。
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
//构造一个新的,空的集合; 支持HashMap实例具有指定的初始容量和默认负载因子(0.75)。
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
//构造一个新的,空的链接散列集。 (此包私有构造函数仅由LinkedHashSet使用。)
//后缀HashMap实例是具有指定初始容量和指定负载因子的LinkedHashMap。
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
//返回此集合中元素的迭代器。 元素没有特定的顺序返回。
public Iterator iterator() {
return map.keySet().iterator();
}
//返回此集合中的元素数(其基数)。
public int size() {
return map.size();
}
//如果此集合不包含元素,则返回true
public boolean isEmpty() {
return map.isEmpty();
}
//如果此集合包含指定的元素,则返回true。
//更正式地,当且仅当这个集合包含元素e使得(o == null?e == null:o.equals(e))时,才返回true。
public boolean contains(Object o) {
return map.containsKey(o);
}
//将指定的元素添加到此集合(如果尚未存在)。 更正式地,如果该集合不包含元素e2(e == null?e2 == null:e.equals(e2)),
//则将指定的元素e添加到此集合中。 如果该集合已经包含该元素,则该调用将保留该集合并返回false。
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
//如果存在,则从该集合中删除指定的元素。 更正式地,删除元素e,使得(o == null?e == null:o.equals(e)),如果此集合包含这样的元素。
//如果此集合包含元素(或等效地,如果此集合由于调用而更改),则返回true。 (一旦调用返回,此集合将不包含该元素。)
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
//从该集合中删除所有元素。 此通话返回后,该设置将为空。
public void clear() {
map.clear();
}
//返回此HashSet实例的浅层副本:元素本身不被克隆。
public Object clone() {
try {
HashSet newSet = (HashSet) super.clone();
newSet.map = (HashMap) map.clone();
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
//将这个HashSet实例的状态保存到一个流(即序列化它)。
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
//写出任何隐藏的序列化魔法
s.defaultWriteObject();
//写出HashMap容量和负载因子
s.writeInt(map.capacity());
s.writeFloat(map.loadFactor());
//写出大小
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);
}
//读取大小并验证非负数。
int size = s.readInt();
if (size < 0) {
throw new InvalidObjectException("Illegal size: " +
size);
}
//根据大小和负载因子设置容量,确保HashMap至少满25%,但要钳位到最大容量。
capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),
HashMap.MAXIMUM_CAPACITY);
//创建支持HashMap
map = (((HashSet>)this) instanceof LinkedHashSet ?
new LinkedHashMap(capacity, loadFactor) :
new HashMap(capacity, loadFactor));
//以正确的顺序读入所有元素。
for (int i=0; i spliterator() {
return new HashMap.KeySpliterator(map, 0, -1, 0, 0);
}
}
public class LinkedHashSet extends HashSet implements Set, Cloneable, java.io.Serializable {
private static final long serialVersionUID = -2851667679971038690L;
//构造一个具有指定的初始容量和负载因子的新的,空的链接散列集。
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
//构造具有指定的初始容量和默认负载因子(0.75)的新的,空的链接散列集。
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
//构造一个具有默认初始容量(16)和负载因子(0.75)的新的,空的链接散列集。
public LinkedHashSet() {
super(16, .75f, true);
}
//构造与指定集合相同的元素的新的链接散列集。
public LinkedHashSet(Collection extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
public Spliterator spliterator() {
return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);
}
}