菜鸟学JAVA之——集合框架(二)(Set接口的实现类HashSet、LinkedHashSet、TreeSet)

Set接口

如果有人告诉你Set是无序的,那你可以直接回怼他这是错的,说法不严谨。

Set接口的实现类(都不能放重复值)

​ 1.HashSet(无序)

​ 2.LinkedHashSet(有序)

​ 3.TreeSet(有序)

没有ArraySet,这是因为Array是连续的,Set是不连续的;

  • Set与List的相同点,也是Collection的子接口,也是容器

  • Set才叫真正意义上的集合,List叫做列表

  • 集合与列表的区别:

    列表是一条一条记录的,而集合是围在一起的

    比如,有五个人,他们整整齐齐做一列就是列表,要是围一堆坐着就是集合,不知道谁是头,谁是尾

    Set集合是没有脚标的,所以Set里面也没有get方法,List有脚标,所以可以有get方法,List和Set是兄弟关系,这也正是Collection接口里没有get方法的原因。

  • 集合中不能放重复的对象,这是因为他没有脚标。所以Set集合可用来去重

  • Set有点像水壶,茶壶里煮饺子,倒不出来。要是想从Set里拿出来,则必须把所有的值都拿出来

HashSet是无序的,注意是HashSet不是Set

forezch在底层使用迭代器实现的

如果一个类没有迭代器,则它不能使用foreach循环

iterator.remove();不能连着使用

  • 怎么解释hashset是无序的,怎么解释set不能放重复元素?

    因为hashSet的底层是按照hash算法排列得到的数列,他是一个不可逆的算法。每个对象都有一个hashcode,hash算法通过hashcode来排数据,所以hashset无序。

    HashSet底层由HashMap实现,插入的元素被当做是HashMap的key,根据hashCode值来确定集合中的位置,在向HashMap中添加元素时,先判断key的hashCode值是否相同,如果相同,则调用equals()、==进行判断,若相同则覆盖原有元素;如果不同,则直接向Map中添加元素;

set的两个主要实现类,TreeSet和HashSet,底层存储结构都是用的map,而且是将set需要存储的值放在map的key里的,value是一个空的object对象。

在这里插入图片描述

  • 那有没有有序的set呢

    有,LinkedHashSet, 往里放的什么顺序,打印出来的就是什么顺序,以链表的形式存当前的元素,只是链表位置被hash了,但是它没有下标

    还有一个有序的set,TreeSet。按comparable升序排列,它的底层实现是二叉树

TreeSet有个约束,往它里面放到内容必须实现comparable接口

一、HashSet

在向HashMap中添加元素时,先判断key的hashCode值是否相同,如果相同,则调用equals()、==进行判断,若相同则覆盖原有元素;如果不同,则直接向Map中添加元素;

public class Main {
    public static void main(String[] args) {
        Set<String> sets = new HashSet<>();
        sets.add("zhang");
        sets.add("ao");
        sets.add("qi");
        sets.add("zhang");
        sets.add("san");
        Iterator<String> iterator = sets.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        } //输出:san   qi    zhang   ao  //无序的且不重复
        sets.remove("ao");//删除元素
        sets.clear(); //清空容器
    }
}

二、LinkedHashSet(直接父类是 HashSet)

特点:存取有序,存储的元素不能重复。

Set<String> sets = new LinkedHashSet<>();
        sets.add("a");
        sets.add("a");
        sets.add("a");
        sets.add("b");
        sets.add("b");
        sets.add("c");
        sets.add("d");
        for (String str:sets
             ) {
            System.out.println(str);
        }
//输出a   b   c   d

三、TreeSet( 底层结构为红黑树

与HashSet不同的是,TreeSet具有排序功能,分为自然排序(123456)和自定义排序两类,默认是自然排序;在程序中,我们可以按照任意顺序将元素插入到集合中,等到遍历时TreeSet会按照一定顺序输出–倒序或者升序;

方式一: 让元素所在的类实现Comparable接口,并重写CompareTo() 方法,并根据CompareTo()的返回值来进行添加元素

  • 返回正数:往二叉树的右边添加
  • 返回负数:往二叉树的左边添加
  • 返回 0 : 说明重复,不添加

方式二: 使用TreeSet的有参构造方法创建TreeSet对象的时候, 传入一个比较器 Comparator 进去, TreeSet在添加元素的时候, 根据比较器的compare()方法的返回值来添加元素。

  • 返回正数:往二叉树的右边添加
  • 返回负数:往二叉树的左边添加
  • 返回 0 : 说明重复,不添加

TreeSet存储元素对元素进行排序的源码解析
TreeSet在存储元素的时候会首先去判断是否有比较器存在(也就是判断比较器是否为null),如果存在:就会让比较器去调用compare(T t1, T t2)方法,去依次比较即将存入的值和已经存入TreeSet集合的值,如果返回正数:往二叉树右侧放;如果返回负数:往二叉树左侧放;如果返回 0 :不添加。如果不存在:底层就会把即将存入的元素自动提升为Comparable类型的对象(所以如果没有比较器的情况下,元素所在的类没有实现Comparable接口,在做自动提升类型的时候就会报类型转换错误),并让该对象调用CompareTo(T t)方法,和已经存入TreeSet集合的元素依次比较,如果返回正数:往二叉树右侧放;如果返回负数:往二叉树左侧放;如果返回 0 :不添加。所以,如果两种方式同时使用,底层会优先使用方式二(比较器的方式)。
在这里插入图片描述

学习参考:
https://blog.csdn.net/Qingai521/article/details/87968134
https://www.baidu.com/link?url=o4mGbw9BArl9kO8SxYj_9jYdwjO5FsfggK8FpB6CCxsj1SxlIhSRsx7_3mAu_2F3&wd=&eqid=a848f8fb0007e998000000035dfaf2c7

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章