探索HashSet底层实现
前言
HashSet的底层实现依赖于HashMap,所以它的数据结构也是数组 + 链表 + 红黑树,而对于它的类注释也没什么好总结的,探索HashSet底层实现是基于JDK1.8。仔细一想,HashSet存在的意义是什么?有时候需要添加元素时,也就是只有单个对象,并没有所谓的键值对,或许还有些用处,可这ArrayList也能做到啊!可是相比之下,HashSet由于有HashMap撑腰,它的性能要高于ArrayList,所以我认为HashSet是List和Map独有的特性结合后的产物。
数据结构
//可序列化、可克隆
public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {
//直接使用了HashMap来存储它的元素
private transient HashMap<E,Object> map;
//既然用了HashMap就要考虑值应该存什么,就是它了,不管新增的元素是什么,它都作为值
private static final Object PRESENT = new Object();
}
构造函数
/**
* 初始化
*/
public HashSet() {
map = new HashMap<>();
}
/**
* 指定集合来初始化
* @param c 指定集合
*/
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
/**
* 指定初始容量与加载因子来初始化
* @param initialCapacity 指定初始容量
* @param loadFactor 指定加载因子
*/
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
/**
* 指定初始容量来初始化
* @param initialCapacity 指定初始容量
*/
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
/**
* 指定初始容量与加载因子来初始化
* 对比上面这里构造了LinkedHashMap,说明它是有序的
* @param initialCapacity 指定初始容量
* @param loadFactor 指定加载因子
* @param dummy 无实际意义,为了与上面的构造函数区分开来
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
简单方法
/**
* 获取迭代器
* @return 迭代器
*/
public Iterator<E> iterator() {
return map.keySet().iterator();
}
/**
* 获取元素个数
* @return 元素个数
*/
public int size() {
return map.size();
}
/**
* HashSet是否为空
* @return 是否为空
*/
public boolean isEmpty() {
return map.isEmpty();
}
/**
* HashSet是否包含指定元素
* @param o 指定元素
* @return 是否包含指定元素
*/
public boolean contains(Object o) {
return map.containsKey(o);
}
/**
* 新增元素
* @param e 指定元素
* @return 是否新增成功
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
/**
* 移除指定元素
* @param o 指定元素
* @return 是否移除成功
*/
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
/**
* 清空
*/
public void clear() {
map.clear();
}
/**
* 浅克隆
*/
public Object clone() {
try {
HashSet<E> newSet = (HashSet<E>) super.clone();
newSet.map = (HashMap<E, Object>) map.clone();
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
总结
-
HashSet无序、不可重复、非线程安全。
-
HashSet允许存放空元素。
-
HashSet底层基于HashMap。
-
两个相等的对象,即hashCode与equals都相等的情况,HashMap底层只是进行值替换,并未理睬键,所以就呈现了在往HashSet添加相等的对象时,只添加了第一个对象,第二个对象并未添加。
重点关注
基于HashMap
浙公网安备 33010602011771号