你应该先学习HashMap
介绍
- 不能包含重复元素
- 无序的
- 底层使用HashMap
- 允许存储null值
- 不是线程安全的
- 具有fail-fast机制
继承关系 继承类介绍
- AbstractSet:该类提供了Set接口的基本实现,以减少实现该类所需要的工作
- Set:不包含重复元素的集合的顶层接口
- Cloneable:可被克隆
- Serializable:可被序列化
源码解析 变量解析 构造函数 常用方法解析
变量解析
// map HashSet是通过HashMap实现的
private transient HashMap<E,Object> map;
// HashMap的value 用来占位的虚值
private static final Object PRESENT = new Object();
构造函数
//默认的构造函数
HashSet()
//构造一个包含指定集合的新集合
HashSet(Collection < ? extends E > c){
/*
为什么要在指定初始容量的地方做这个计算?
先说c.size()/.75f) + 1,首先要知道HashMap的阈值计算是
16 * 0.75,这里通过c的size/0.75+1得到c需要的初始容量
举个例子:c的zise = 50 / .75 + 1 = 67
67就是初始容量,阈值 = 67 * 0.75 = 50 结果刚好是c的size
这样新创建HashMap的初始容量阈值就刚好是c的size了
再说这个16:如果c.size()/.75f) + 1得到的结果小于16,那么还是指定默认的
初始容量
为什么是16? 整数次幂的原因 HashMap再细说吧.
*/
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
}
//指定初始容量和指定负载因子
HashSet( int initialCapacity, float loadFactor)
//指定初始容量
HashSet( int initialCapacity)
//这个构造是私有的
HashSet( int initialCapacity, float loadFactor, boolean dummy)
常用方法解析
add(E e)
作用:如果这个集合不包含元素e,则将指定的元素e添加到这个集合中
public boolean add(E e) {
/**
* 数据用作key PRESENT用作value的占位符
*/
return map.put(e, PRESENT)==null;
}
remove(Object o)
作用:删除一个元素,如果这个集合包含这样一个元素
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
…都是用map实现的…
其他
- 记得在写Collection时好像说了HashSet如何做到数据唯一的,这里就验证了数据唯一是因为HashMap,它不能违反HashMap唯一Key原则
- 如果你想使用HashSet来存储你的类的对象,那么你必须覆盖hashCode()和equals()方法,否则两个逻辑上相同的对象将被认为是不同的,因为当你向集合中添加一个项时,会调用对象hashCode()类(最有可能为您的对象返回不同的哈希码)。
- 总结一下,使用HashMap实现,HashSet不是以Key-value形式存储数据,Value使用占位符,其他需要学习HashMap来掌握了
2019/6/18 21:42:23