简介
HashSet底层是基于HashMap来实现的,是不允许有重复的元素的,如果添加相同的元素则会替换value,HashSet插入顺序是无序的,如果熟悉HashMap的代码再来看HashSet的代码则会很简单。
HashSet关系图
变量
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
map则是在创建HashSet的时候创建,将元素添加到HashSet中其实就是添加到HashMap中,HashMap存储的方式是键值对,而HashSet中只能传递键,那值从哪来呢?PERSENT则是用于填充HashMap中的值。
构造函数
从HashSet的构造方法能看出来其实就是创建了一个HashMap
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);
}
add方法
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
add方法最终调用的是HashMap中的put方法,添加的对象e为键,而值是固定的PRESENT,如果map中存在该键则会将值替换掉,因为值是固定的,替换与不替换没有什么关系,如果map中不存在该键则会直接将键值添加到map中。
addAll方法
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
addAll方法则是AbstractCollection中的方法,而HashSet是间接继承了AbstractCollection中的方法,从addAll方法中的代码来看则是将指定集合中的元素循环调用add方法添加到HashSet中,modified则表示HashSet是否被修改也可以表示是否有元素被添加到HashSet中。
remove方法
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
remove方法则是根据指定的键从map中删除元素,根据指定的键的值来判断元素是否被删除,如果元素不存在或删除失败,值返回的则是null,则不等于固定的值PRESENT,元素删除成功,值返回的肯定是固定的PRESENT。
removeAll方法
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
if (size() > c.size()) {
//遍历待删除的元素集合并将元素从当前集合中删除
for (Iterator<?> i = c.iterator(); i.hasNext(); )
modified |= remove(i.next());
} else {
//遍历当前集合并校验待删除的元素集合中是否包含当前集合中的元素
//如果包含则从当前集合中删除
for (Iterator<?> i = iterator(); i.hasNext(); ) {
if (c.contains(i.next())) {
i.remove();
modified = true;
}
}
}
return modified;
}
HashSet并没有重写removeAll方法,而是AbstractSet继承了AbstractCollection并重写了removeAll方法,如果当前集合的长度大于待删除的元素集合长度则使用迭代器遍历待删除的元素集合并调用HashSet的remove方法将元素从集合中删除,如果小于则获取当前集合的迭代器遍历集合并校验待删除的元素集合中是否包含当前遍历到的元素,包含则删除。
contains方法
public boolean contains(Object o) {
return map.containsKey(o);
}