JAVA常用集合源码分析:HashSet

序言

在上一篇文章中,我们介绍了HashMap,其实本来想自己完成源码分析的一系列文章的,但是HashMap的源码着实是复杂,看的我脑壳疼。。于是就自己去找了找大牛们的文章反复看,后面总算有了点门道了,大致知道了HashMap的原理,然后转载了一篇我认为总结的比较好的文章到我的博客里,供大家一起学习。初步了解HashMap的源码后,自以为自己还OK了,于是便打算独立把ConcurrentHashMap的源码也一并分析完,然后写下来,可是一看代码行数

《JAVA常用集合源码分析:HashSet》

我。。。。给跪了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有的问题它都有)
    原文作者:java集合源码分析
    原文地址: https://blog.csdn.net/qq_37410328/article/details/82925830
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞