HashSet是一种存储不可重复元素的集合,元素在集合中是无序的(元素不是按照添加顺序存储)。
特点
- 元素不可重复:依据hash值和元素内容进行判断,若添加的元素与已有元素重复,则不会添加
- 元素是无序的:元素存放位置是根据hash值随机分布的
- 允许null值:集合中允许存放null值
- 非线程安全:没有多线程操作支持,若需要支持线程安全,可使用Collections.synchronizedSet()或其他并发容器
设计原理
- HashSet底层数据结构是基于HashMap实现的,具有HashMap的所有特点(数据结构是素组+链表+红黑树)
- HashSet中的HashMap实际只在key存储真实元素,value值是一个固定的常量
- HashSet中的HashMap默认初始化容量为16,当元素数量达到容量的75%时,数组会扩容到原来的2倍
- HashSet中的HashMap,链表长度达到8并且数组长度达到64,链表会进行树化
- HashSet在首次添加元素时进行初始化,减少内存占用
- HashSet的实现是基于适配器模式(通过包装HashMap的接口,适配成Set接口的方式)
方法
构造方法
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
static final long serialVersionUID = -5024744406713321676L;
//存储元素的map
private transient HashMap<E,Object> map;
//map中value存放的元素(是一个常量)
private static final Object PRESENT = new Object();
//创建一个空的HashSet
public HashSet() {
map = new HashMap<>();
}
//创建一个新的map,将传入的Collection集合元素放入map中
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
//指定初始化容量和扩容因子的map集合
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
//指定初始化容量
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
}
添加单个元素
//实际调用HashMap中的put方法,key是实际元素,value是一个常量
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
删除元素
//删除某一个元素
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
添加多个元素
//使用的是抽象类AbstractCollection中的方法,循环体中的add(e)是HashSet自行实现的
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
是否包含某个元素
//实际调用HashMap的containsKey方法
public boolean contains(Object o) {
return map.containsKey(o);
}
迭代器
//调用的是HashMap中的keyset迭代器
public Iterator<E> iterator() {
return map.keySet().iterator();
}