序言
在上一篇文章中,我们介绍了HashMap,其实本来想自己完成源码分析的一系列文章的,但是HashMap的源码着实是复杂,看的我脑壳疼。。于是就自己去找了找大牛们的文章反复看,后面总算有了点门道了,大致知道了HashMap的原理,然后转载了一篇我认为总结的比较好的文章到我的博客里,供大家一起学习。初步了解HashMap的源码后,自以为自己还OK了,于是便打算独立把ConcurrentHashMap的源码也一并分析完,然后写下来,可是一看代码行数
我。。。。给跪了orz 算了算了改天再来吧
HashSet
算了,回到正文,我们先来回想下HashSet是个啥?它也是个集合类(废话…),可以存储对象,但是存储是无序的,不可以存取重复的对象…有了这些印象,我们就带着问题来分析源码
- 为什么是无序
- 为什么不可以存储重复对象
结构
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
没有什么特别的东西,很常用的继承结构,一步一步慢慢分解下来,中间用抽象类来缓冲下面实现集合的工作量
实现的Set接口,这个是多余的东西,可以不实现它,因为在AbstractSet中已经实现了set接口了,继承了AbstractSet,就相当于也实现了Set接口
Cloneable:能够使用clone方法,目的是为了在数组扩增大小的时候,能用到此方法
Serializable:能够使之序列化
属性
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
哇,巨简单有木有!就两个属性!
根据这个属性,我们也可以得出结论
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);
}
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
虽然构造函数有好几个,但是都是initalCapacity(初始容量) loadFactor(负载因子)这些的组合而已,最后都是调用HashMap的构造方法对map进行初始化
常用方法
1.add(E)
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
这个方法是我们用的最多的方法,然鹅它的实现只有短短一行…这也进一步说明HashSet是靠底层的HashMap实现的。从这个方法中,我们可以发现set中的每一个值,都被当做一个key存储在HashMap中,对应的value都是PRESENT,这也解释了为什么HashSet的值是不能重复的,因为map中的key是不能重复的,当有重复的值写入到HashTree中,value值会被覆盖,key值不受影响。
同样,map中的值是无序的,所以TreeSet的值也是无序的啦。
2.remove(Object) 删除一个对象
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
同样是调用map的删除方法,至于其他的一些方法,也都大同小异,就不展开叙述啦
3.为什么没有get(index) 这个方法
因为是无序的呀!
4.那么要如何遍历呢?
//增强for循环遍历
for(String s: set){
System.out.println(s);
}
//迭代器遍历
Iterator<String> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
总结
HashSet是我读过最简单的源码啦2333,毕竟复杂的操作都交给HashMap去实现啦,HashSet只要几行代码调用下就ok,巨简单
最后再回顾下HashSet的特点
- 元素没有顺序(底层用的是HashMap,HashMap本身中的元素度没有顺序,那么HashSet更不可能有了)
- 元素不能重复(HashSet中存放的元素,度是当作HashMap的key来使用,HashMap中key是不能相同的,所以HashSet的元素也不能重复了)
- 非线程安全(HashMap有的问题它都有)