源码解读--HashSet
一.序言
先说一下HashSet的特性:添加的是对象;值不会重复;内部实现用的是HashMap。java源码系列。
老套路,看看图谱,看它是何方神圣。
简单的来说,好像没发现什么,就是Set集合而已。
二.源码
精简一点,和之前一样,只讲解一两个增删查的方法,更深的需要同学们去发掘。
1初始化
它有五个初始化方法HashSet(),HashSet(Collection),HashSet(int),HashSet(int ,float),HashSet(int ,float,boolean)
1.1 HashSet()方法
public HashSet() { //直接就建了一个HashMap对象,我们都知道Map是K-v接口,按道理有两个呀,HashSet但是只存一个值,什么情况?不急,我们往下看。 map = new HashMap<>(); }
1.2 HashSet(Collection) 方法
public HashSet(Collection<? extends E> c) { //初始化的时候添加的是一个集合,这个HashMap的初始容量设置为,(集合个数*1.25 +1)和16取最大值 map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); //把这个集合加到这个map中 }
public boolean addAll(Collection<? extends E> c) { //具体添加方法 boolean modified = false; for (E e : c) if (add(e)) //这里有意思了,看下面贴出来的方法 modified = true; return modified; }
public boolean add(E e) { //哈哈 ,被我抓住了,原来key是我们的添加的值,V 是一个对象 return map.put(e, PRESENT)==null; //PERSENT定义为 private static final Object PRESENT = new Object() 没看错, 就是一个对象
}
1.3HashSet(int) 方法
public HashSet(int initialCapacity) { //初始HashMap的容量 map = new HashMap<>(initialCapacity); }
1.4 HashSet(int ,float) 第一个参数是容量,第二个参数我猜猜看,应该是负载因子吧,不信看源码
public HashSet(int initialCapacity, float loadFactor) { //看,没骗你吧 map = new HashMap<>(initialCapacity, loadFactor); }
1.5HashSet(int ,float,boolean) 那第三个参数是什么呢?
HashSet(int initialCapacity, float loadFactor, boolean dummy) { 逗我玩呢? dummy 这个参数根本就没有用 map = new LinkedHashMap<>(initialCapacity, loadFactor); }
2.添加 (重点)
public boolean add(E e) { //纳尼,这就完了,不是说key相同的会覆盖吗?怎么体现的? return map.put(e, PRESENT)==null; //这里面用的是HashMap,简单教大家一个记忆方法,HashMap的key是不是唯一的?对的,你们一般都是这样回答的,那这里HashSet里面的值也是唯一的,我记得HashMap可是支持Null作为key,也就是HashSet可以存放null。HashMap里面的东西这里就不累述了。 }3.删除
public boolean remove(Object o) { //这里调用的是HashMap里面的remove方法, return map.remove(o)==PRESENT; //判断移除的对象是对象,因为HashSet存的时候对应hashMap的V也是对象 }
4 查找
public boolean contains(Object o) { //我去,又是map的方法, return map.containsKey(o); }说实话,今天我也是第一次看HashSet源码,没想到里面的实现竟然是HashMap,那这么说HashMap的问题,它都有咯
1.顺序不固定,我们知道HashMap会扩容,之后顺序高低位不一样(jdk8是这样,jdk是再hash,hash的自然是新数组的长度哈),
2.不是线程安全的。
三.使用
public void HashSetTest() { Set<String> strings = new HashSet<String>(); strings.add("a"); strings.add("b"); strings.add("c"); strings.add("a"); for (String s : strings) { System.out.println(s); } }
输出:
a
b
c
探究:到底这个输出的a是代码中第一个存入的a,还是第四个存入的a?
看过源码就知道,HashMap在添加值的执行,先找map里面有没有key相同的,如果找到了,这个key是不动的,只是把值(V)覆盖了,HashMap找到key跟新值(v)源码如下:
if (e != null) { // 找到我们的key相同的,key没有动,到时值被赋了新值 V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; }