【容器集合】------>Set集合

在这里插入图片描述

Set

  上一篇文章大概地讲了一下List集合,本篇文章我们就来了解一下Set集合

Set集合的概述和特点

依旧是那张结构图👇:

  从结构图中可以看到Set集合继承于Collection接口,是一个不允许出现重复元素且没有顺序的集合,主要的实现类有HashSetTreeSet两大实现类;


HasSet

特点

- 底层数据结构是哈希表
 - 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
 - 没有带索引的方法,所以不能使用普通for循环遍历
 - 由于是Set集合,所以是不包含重复元素的集合

  前面说到Set集合不允许出现重复的元素,在存储元素时,要保证元素唯一性需要重写hashCode()和equals()方法

 如果元素的hashCode值相同,才会判断equals是否为true
 
 如果hashCode的值不同,不会调用equals方法

注意❗️:对于判断元素是 否存在,以及删除等操作。依赖的方法是元素的hashCode和equals方法。

public static void main(String[] args) {
		//创建学生对象
        Student s1 = new Student("富贵", 23);
        System.out.println(s1.hashCode());
        System.out.println(s1.hashCode());
        System.out.println("————————————");

        //创建第二个学生对象
        Student s2 = new Student("富贵", 23);
        System.out.println(s2.hashCode());
    }
运行结果:
356573597
356573597
————————————
1735600054

  从👆程序中可以看到同一个对象多次调用hashCode()方法返回的哈希值是相同的,不同对象调用hashCode()方法的哈希值是不同的

  哈希值 是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值

HashSet集合的基本使用:

public static void main(String[] args) {
        HashSet<String> hs = new HashSet<>();//创建集合对象
        //添加元素
        hs.add("富贵");
        hs.add("招财");
        hs.add("富贵");
        //遍历集合
        for (String s : hs) {
            System.out.println(s);
        }
    }

运行结果:
富贵
招财

HashSet集合保证元素唯一性源码分析流程图

在这里插入图片描述

  说了这么多不如看一下实际操作:
需求:

创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合

要求:学生对象的成员变量值相同,我们就认为是同一个对象

按照需求先新建一个学生类:

public class Student {
    private String name;
    private int age;

 /*省略了构造方法和get、set方法………………*/
 
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;

        if (age != student.age) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
}

测试类:

public class HashSetDemo {
    public static void main(String[] args) {
        //创建HashSet集合对象
        HashSet<Student> hs = new HashSet<Student>();

        //创建学生对象
        Student s1 = new Student("富贵", 28);
        Student s2 = new Student("招财", 25);
        Student s3 = new Student("进宝", 45);

        Student s4 = new Student("进宝", 45);

        //把学生添加到集合
        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);

        //遍历集合(增强for)
        for (Student s : hs) {
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}

运行结果:
招财,25
富贵,28
进宝,45


LinkedHashSet

特点

- 哈希表和链表实现的Set接口,具有可预测的迭代次序
- 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
- 由哈希表保证元素唯一,也就是说没有重复的元素

基本使用:

public class LinkedHashSetDemo {
    public static void main(String[] args) {
        //创建集合对象
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();

        //添加元素
       linkedHashSet.add("富贵");
        linkedHashSet.add("招财");
        linkedHashSet.add("进宝");
        linkedHashSet.add("富贵");

        //遍历集合
        for(String s : linkedHashSet) {
            System.out.println(s);
        }
    }
}

运行结果:
富贵
招财
进宝


TreeSet

讲TreeSet集合之前先看先看一段代码:

public class TreeSetDemo {
    public static void main(String[] args) {
        //创建集合对象
        TreeSet<Integer> ts = new TreeSet<Integer>();
        //添加元素
        ts.add(10);
        ts.add(40);
        ts.add(30);
        ts.add(50);
        ts.add(20);
        ts.add(30);

        //遍历集合
        for (Integer i : ts) {
            System.out.println(i);
        }
    }
}
运行结果:
10
20
30
40
50

结论:

  • 元素有序,可以按照一定的规则进行排序,具体排序方式取决于构造方法
- TreeSet():根据其元素的自然排序进行排序
- TreeSet(Comparator comparator) :根据指定的比较器进行排序
  • 没有带索引的方法,所以不能使用普通for循环遍历
  • 由于是Set集合,所以不包含重复元素的集合

自然排序Comparable

  还是先看一个案例,从案例中来分析
需求:

- 存储学生对象并遍历,创建TreeSet集合使用无参构造方法
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

实现步骤

- 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
- 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
- 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

先新建一个学生类

public class Student implements Comparable<Student> {
    private String name;
    private int age;
 /*省略了构造方法和get、set方法………………*/
    @Override
    public int compareTo(Student s) {
        //按照年龄从小到大排序
       int num = this.age - s.age;//主要条件
       
	//从大到小排序
    // int num = s.age - this.age;
       
        //年龄相同时,按照姓名的字母顺序排序
       int num2 = num==0?this.name.compareTo(s.name):num;//次要条件
        return num2;
    }
}

测试类

public class TreeSetDemo {
    public static void main(String[] args) {
        //创建集合对象
        TreeSet<Student> ts = new TreeSet<Student>();
        //创建学生对象
        Student s1 = new Student("富贵", 29);
        Student s2 = new Student("招财", 28);
        Student s3 = new Student("进宝", 30);
        Student s4 = new Student("钱多多", 33);

        Student s5 = new Student("莱福",33);
        Student s6 = new Student("莱福",33);

        //把学生添加到集合
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);

        //遍历集合
        for (Student s : ts) {
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}

运行结果:
招财,28
富贵,29
进宝,30
莱福,33
钱多多,33

结论

无参构造方法使用的是自然排序对元素进行排序的
自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(To)方法
在学生类实现Comparable接口
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

比较器排序Comparator

  按照步骤先看案例
需求

- 存储学生对象并遍历,创建TreeSet集合使用带参构造方法
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

实现步骤

- 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
- 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法
- 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

学生类

public class Student {
    private String name;
    private int age;
   /*省略了构造方法和get、set方法………………*/
}

测试类

public class TreeSetDemo {
    public static void main(String[] args) {
        //创建集合对象
        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
            
                int num = s1.getAge() - s2.getAge();//主要条件
                int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;//次要条件
                return num2;
            }
        });
        //创建学生对象
         Student s1 = new Student("富贵", 29);
        Student s2 = new Student("招财", 28);
        Student s3 = new Student("进宝", 30);
        Student s4 = new Student("钱多多", 33);

        Student s5 = new Student("莱福",33);
        Student s6 = new Student("莱福",33);
        //把学生添加到集合
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);

        //增强for遍历集合
        for (Student s : ts) {
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}
运行结果:
招财,28
富贵,29
进宝,30
莱福,33
钱多多,33

结论

用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写comparetor(To1,To2)方法
在构造方法中传递一个Comparator比较器接口
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

在这里插入图片描述


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值