前言
Set不保存重复的元素。Set中最常被使用的是测试归属性,你可以很容易的询问某个对象是否在某个Set中。Set具有与Collection完全一样的接口,因此没有任何额外的功能。实际上Set就是Collection,只是行为不同。
Set接口
Set接口内容如下图:
从上图中我们可以很清晰的看出,Set接口继承了Collection接口,甚至可以说Set接口就是Collection接口。
常用实现类
Set
|------HashSet
| |-------LinkedHashSet
|------TreeSet
HashSet
HashSet是基于HashMap来实现的,操作很简单,更像是对HashMap做了一次“封装”,而且只使用了HashMap的key来实现各种特性。
内部成员
// HashSet内部包含了一个HashMap
private transient HashMap<E,Object> map;
// 定义一个虚拟的Object。
// PRESENT是向map中插入key-value对应的value
// 向map中添加键值对时,键值对的值固定是PRESENT
private static final Object PRESENT = new Object();
初始化
HashSet提供如下四种初始化方法:
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的初始化过程可以看作是内部HashMap的初始化过程,不再赘述。
关键方法
正如前言中所述,Set不保存重复的元素,Set中最常被使用的是测试归属性。Set中最频繁被调用的方法就是add、remove、contains三个方法。
add方法
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
add方法的实现逻辑就是往内部成员map中添加e和PRESENT组成的键值对,根据返回值是否为null判断是否添加成功。HashMap中如果内部已经存在key为e的键值对,则返回对应的value,否则返回null。此处可以看到,HashSet内部的map中所有键值对的value都是PRESENT。
remove方法
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
remove方法调用HashMap的remove方法,根据返回值判断是否删除成功。
contains方法
public boolean contains(Object o) {
return map.containsKey(o);
}
contains方法通过调用HashMap的containsKey方法判断是否包含相关对象。
LinkedHashSet
LinkedHashSet继承自HashSet,源码更少、更简单,唯一的区别是LinkedHashSet内部使用的是LinkHashMap。这样做的意义或者好处就是LinkedHashSet中的元素顺序是可以保证的,也就是说遍历序和插入序是一致的。
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
public LinkedHashSet() {
super(16, .75f, true);
}
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
LinkedHashSet通过调用HashSet包私有的构造方法来初始化,使用LinkedHashMap代替HashMap作为对象的存储载体。
总结
本文主要讲述了Set接口及其部分实现类的内部逻辑,Set接口的更多高级实现,例如TreeSet后续还会有讲述,希望能对读者有所帮助。