Java集合系列-Set系列-HashSet

    xiaoxiao2022-07-13  146

    本篇文章的主要内容:

    1:Set集合的特点 2:HashSet的实例说明 3:根据上面的实例来跟踪HashSet的源码 4:LinkedHashSet的讲解 一、Set集合的特点 1:Set集合是无序的,就是说存入的顺序和取出的顺序不一定一致 2:Set集合是不能重复的 3:因为Set集合是无序的,所以不提供get(int index)这样通过下标获取的方法。 上面的Set特点相信大家都非常的清楚,这里列出来只是引出下面的内容,没有什么好解释的,Set集合有两个非常重要的实现类,一个是HashSet,另一个是TreeSet.本篇文章我主要介绍HashSet。

    二、HashSet的实例 public static void main(String[] args) { Set set = new HashSet<>(); set.add(1); set.add(null); set.add(3); set.add(1); set.add(10); set.add(2); System.out.println(“Set集合的大小:”+set.size()); System.out.println(“遍历Set集合如下:”); for(Integer i:set){ System.out.print(i+" "); } } 上面的实例运行结果如下:

    Java集合系列-Set系列-HashSet 从上面的运行结果可以看到,添加6个元素,但是返回的Set集合大小:5,和实际的相比较少了一个,上面1添加两次,说明Set集合是不能重复添加相同元素的,从下面的遍历顺序不是添加元素的顺序,所以证明Set集合添加元素的顺序和获取元素的顺序不一定相同。那么HashSet是通过怎样的规则来遵循Set无序和唯一的规则的呢?接下来我们从源码角度去分析以下。

    三、HashSet的源码解析 Java集合系列-Set系列-HashSet 1、HashSet的成员变量

    第一个重要的成员变量:map

    private transient HashMap<E,Object> map; HashSet内部定义了一个HashMap的成员变量,我们知道HashSet是属于Set集合,而HashMap属于Map集合,那为什么在HashSet中定义一个Map集合呢?它是起到什么作用呢?

    第二个重要的成员变量:PRESENT

    private static final Object PRESENT = new Object(); 定义一个对象常量,而且被final修改,说明不能修改,这个成员变量又是干什么的呢?

    HashSet就定义了这两个成员变量,让人非常的疑惑不解,带着这两个问题,我们解析了继续分析HashSet的构造函数。

    2、HashSet的构造方法

    第一个构造函数:

    public HashSet() { map = new HashMap<>(); } 第二个构造函数:

    public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } 第三个构造函数:

    public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } 第四个构造函数:

    public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll©; } 第五个构造函数:

    //这一个构造函数没有被public修饰,和上面4个又不太一样,这一个是LinkedHashSet使用的,因为LinkedHashSet继承了HashSet,这篇文章末尾会讲解 HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); } 从构造函数中我们可以发现,都是创建了一个HashMap对象,然后赋值给上面的成员变量map,从构造函数中我们仍然看不出来上面两个成员变量是干什么用的,构造函数中我们看不出来,那我们继续分析HashSet的方法,看是否能够找到突破口,你就记住,HashSet的构造函数就干了一件事:创建一个HashMap对象,然后赋值给成员变量。

    3、HashSet的重要方法

    因为是集合,所以无外乎增删改查几个方法。我们一个一个的去分析。

    3.1、add方法

    public boolean add(E e) { return map.put(e, PRESENT)==null; } 大家看到这个方法是不是恍然大悟,HashSet的底层实现其实就是通过HashMap实现的,而我们添加的元素就是HashMap的key,成员变量RESENT就是HashMap的value,是不是非常的简单,别看只有一句代码,完全解释了HashSet怎样实现Set集合的无序和唯一的特点的。

    1:无序:我们知道HashMap是利用hash计算的下标存入的,它是无序的,HashSet新增的元素作为HashMap的key,所以是无序的。 2:唯一:对于HashMap的key如果是相等,新增时如果已经存在了,在增加相同的key时会覆盖以前的旧值,所以能够保证有唯一的key,进而HashSet元素不能重复,是唯一的。 3:HashSet没增加一个元素e,就会向底层HashMap中添加一个key=e的元素,如果已存在key,则覆盖。而key对象的值是相同且不变的:PRESENT 3.2、remove方法

    public boolean remove(Object o) { return map.remove(o)==PRESENT; } 3.3、clear方法

    public void clear() { map.clear(); } 3.4、其他方法

    public boolean contains(Object o) { return map.containsKey(o); }

    public boolean isEmpty() { return map.isEmpty(); }

    public int size() { return map.size(); } 上面的方法都是调用HashMap中的方法,如果对HashMap理解不透彻的,请观看我前面的几篇文章,详细你对HashMap熟悉了,HashSet简直没有什么可以说的。

    上面我把HashSet的重要方法都列了出来,但是大家发现没有,并没有像List的get方法,因为HashSet底层是通过HashMap实现的,所以它无序,不能通过什么索引获取指定的元素,也不存在像ArrayList的下标索引。

    HashSet适用于那些对存入顺序和取出顺序没有要求,并且能保证唯一的情景,如果需要保证存入的顺序和取出的顺序一样,那么这时就需要考虑用ArrayList了。

    四、LinkedHashSet的讲解 上面对HashSet做了一个分析,非常的简单,下面我们看一下它的一个子类LinkedHashSet。

    Java集合系列-Set系列-HashSet 上面的图是LinkedHashSet的继承关系,它继承HashSet。在LinkedHashSet中只定义了构造函数,如下:

    public LinkedHashSet(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor, true); } public LinkedHashSet(int initialCapacity) { super(initialCapacity, .75f, true); } public LinkedHashSet() { super(16, .75f, true); } public LinkedHashSet(Collection<? extends E> c) { super(Math.max(2*c.size(), 11), .75f, true); addAll©; } 我在分析HashSet的构造函数时,有一个没有被public修饰的构造,LinkedHashSet的所有构造函数都是调用的那一个构造函数。

    HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); } 从上面可以看到,LinkedHashSet底层不是利用HashMap实现的,而是利用的是HashMap的子类LinkedHashMap实现的。这一篇文章我对LinkedHashMap做了详解,如果对它不了解的,可以仔细看一下。

    如果你对HashMap了解的非常的透彻,在看HashSet是非常的简单的,掌握上面我分析的内容,HashSet你就非常的熟悉了,记住它的两个特点:无序和唯一。

    还有就是这我总结出了一些架构视频资料和互联网公司java程序员面试涉及到的绝大部分面试题和答案做成了文档和架构视频资料还有完整高清的java进阶架构学习思维导图免费分享给大家(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术资料),希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。 料领取方式:加群:374308445填写【 资料】即可免费获取!!! 如果您喜欢本文章,可以点击关注,每天将有更多精彩文章与您分享!

    最新回复(0)