Set只是一个接口,它的具体实现类我们比较熟悉有以下3种:
- HashSet
- LinkedHashSet
- TreeSet
这里就拿最经常用的HashSet做个说明。
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();
public HashSet() {
map = new HashMap<>();
}
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
}
从以上HashSet源码里可以了解到有一个叫PRESENT的常量,更关键的是HashSet的所有构造方法底层其实在都是构建一个HashMap,然后map变量引用指向这个构建的HashMap。
HashSet的add()方法
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
可以发现,HashSet的add()方法其实是以传入的参数对象做为map的key值,value值固定传入PRESENT这个常量,然后调用了HashMap的put()方法。
总结
HashMap本来就是一个不允许有重复key值的集合,而HashSet其实底层用的还是HashMap,只不过是把value值定义成固定的而已。所以与其说HashSet保证了元素的唯一,不如说是HashMap帮助HashSet完成了元素唯一的约束。