前言
HashSet
实现了Set
接口,它的底层是由HashMap
来支持的。HashSet
的元素实际上是存储在底层HashMap
的key
上的。由于HashMap
的无序不重复特性,HashSet
存储的元素也是无序的,并且元素也不能重复,同时也只允许存储一个null
元素。
HashSet源码分析
主要属性:
// HashSet底层map
private transient HashMap<E,Object> map;
// 虚拟对象
private static final Object PRESENT = new Object();
HashSet
是通过HashMap
来保存元素,由于只需要在key
中保存,所以采用虚拟对象PRESENT
对应map
中插入key-value
的value
值的引用。每次向map
中添加元素时,键值对对应的value
都是PRESENT
。
构造函数:
// 默认无参构造
public HashSet() {
map = new HashMap<>();
}
// 根据已有集合元素来构造HashSet
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
// 给定初始容量
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
// 给定初始容量和加载因子
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
// 这个构造函数外部不能调用,供LinkedHashSet复写
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
构造函数都是初始map
,以便加入元素的时候存储。
重要方法:
// 集合大小
public int size() {
return map.size();
}
// 集合是否为空
public boolean isEmpty() {
return map.isEmpty();
}
// 添加元素
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
// 移除元素
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
// 清空集合
public void clear() {
map.clear();
}
// 集合中是否有元素o
public boolean contains(Object o) {
return map.containsKey(o);
}
HashSet
的增删改查,同时直接操作map
来完成的,代码都非常简单。
LinkedHashSet
LinkedHashSet
继承自HashSet
,它的构造方法:
public LinkedHashSet() {
super(16, .75f, true);
}
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
LinkedHashSet
构造方法调用了父类HashSet
的这个构造方法:
// LinkedHashSet复写,初始化LinkedHashMap
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
所以,它的底层是一个LinkedHashMap
,元素的所有操作都是由LinkedHashMap
来维护。LinkedHashSet
与HashSet
的区别和LinkedHashMap
与HashMap
的区别一样,LinkedHashMap
和LinkedHashSet
是有序的,内部由双向链表来记录顺序,而HashMap
和HashSet
都是无序的。
最后
对于HashSet/LinkedHashSet
,只要阅读过HashMap/LinkedHashMap
的源码,基本上就能完全了解它的实现原理。HashSet/LinkedHashSet
中数据的存入、删除、访问都是都是直接操作内部的HashMap
,可以说HashSet/LinkedHashSet
是在HashMap/LinkedHashMap
的基础上加了一层壳。他们唯一的区别就是HashSet/LinkedHashSet
保存的元素时单个的数据或对象,而HashMap/LinkedHashMap
保存的元素时键值对。
网友评论