Set集合
- 1.Set集合特点
- 2.Set集合实现类
- 3. HashSet
- 3.1 底层原理
- 3.1.1 哈希表组成
- 3.1.2 哈希值
- 3.1.3 对象的哈希值特点
 
- 3.2 数据添加元素的过程
- 3.3 HashSet的三个问题
- 3.4 实例:去除重复元素
 
- 4. LinkedHashSet
- 5. TreeSet
- 5.1 特点
- 5.2 集合默认规则
- 5.3 例子
- 5.4 两种比较规则
- 5.4.1 默认排序
- 5.4.2 比较器排序
 
- 5.5. TreeSet对象排序练习
- 5.6 TreeSet小结
- 5.6.1 TreeSet集合的特点?
- 5.6.2 TreeSet集合自定义排序规则有几种方式?
- 5.6.3 方法返回值得特点
 
 
- 6. 单列集合使用场景
1.Set集合特点


2.Set集合实现类

3. HashSet
3.1 底层原理

3.1.1 哈希表组成

3.1.2 哈希值
哈希值:对象的整数表现形式
 

3.1.3 对象的哈希值特点

 
 
 

3.2 数据添加元素的过程

 
 
3.3 HashSet的三个问题
1)
 
 遍历时 是按照数组的索引从0开始读取数据的。当遇到数组索引中存在链表时,就会把数组当前索引里的链表存储的数据全部读取出来后,再继续遍历数组中的下一个索引。数组索引里的数据存储的是红黑树时,也会按照读取树的方法,把数据全部遍历出来后,再继续遍历下一个数组索引。
 
 2)
 
 存储方式不是单一的模式,由 数组,链表,红黑树共同组成。所以无法统一只用一个索引的方式去表述元素。
3)

 用了2个方法去保证元素去重的。
 HashCode 方法
 equals 方法
3.4 实例:去除重复元素

package com.zjut.hashset;
import java.util.HashSet;
public class HashSetDemo1 {
    public static void main(String[] args) {
        /*
        * 需求:创建一个储存学生对象的集合,储存多个学生对象
        *       使用程序实现在控制台遍历该集合
        * 要求:学生对象的成员变量值相同,就认为是同一个对象
        * */
        //1.创建学生对象
        Student stu1 = new Student("zhangsan",23);
        Student stu2 = new Student("lisi",24);
        Student stu3 = new Student("wangwu",25);
        Student stu4 = new Student("zhangsan",23);
        //2.创建集合添加学生
        HashSet<Student> hs = new HashSet<>();
        //3.添加元素
        System.out.println(hs.add(stu1));
        System.out.println(hs.add(stu2));
        System.out.println(hs.add(stu3));
        System.out.println(hs.add(stu4));
        System.out.println(hs);
    }
}
package com.zjut.hashset;
import java.util.Objects;
public class Student {
    private String name;
    private int age;
    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
总结
 当HashSet存储的是自定义类型时,需要重写 equals,hashCode 方法。不然,默认情况是按照对象的地址计算hash值,而不是按照对象的属性计算。就达不到去除重复元素的效果。
4. LinkedHashSet

遍历时,从头节点开始遍历,按照双链表的顺序遍历取出。
 不是再和HashSet那种遍历方法:从数组的0 索引开始遍历,有重复的元素,然后一根一根链表的去查找。
5. TreeSet
5.1 特点

5.2 集合默认规则

字符串从前向后比较
 
5.3 例子
package com.zjut.TreeSet;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo1 {
    public static void main(String[] args) {
        TreeSet<Integer> ts = new TreeSet<>();
        ts.add(4);
        ts.add(5);
        ts.add(3);
        ts.add(2);
        ts.add(1);
        //打印集合
        System.out.println(ts);
        //遍历集合
        //迭代器
        Iterator<Integer> it = ts.iterator();
        while (it.hasNext()) {
            int i = it.next();
            System.out.println(i);
        }
        System.out.println("------------------------------------");
        //增强for
        for (int t : ts) {
            System.out.println(t);
        }
        System.out.println("------------------------------------");
        //lambda
        ts.forEach( integer -> System.out.println(integer));
    }
}
默认从大到小,排好顺序的
 
5.4 两种比较规则
对于自定义的数据类型,可以自定义比较规则。
TreeSet 底层是红黑树,不需要像HashSet一样重写equals,hashCode 方法,才能进行比较。
它有两种比较规则。
 
5.4.1 默认排序

package com.zjut.TreeSet;
import java.util.TreeSet;
public class TreeSetDemo2 {
    public static void main(String[] args) {
        /*
        * 排序方法:
        * 1. Student 实现Comparable接口,重写里面的抽象方法,再指定比较规则
        * */
        //1.创建学生对象
        Student stu1 = new Student("zhangsan",23);
        Student stu3 = new Student("wagnwu",25);
        Student stu2 = new Student("lisi",24);
        //2.创建集合对象
        TreeSet<Student>  ts =new TreeSet<>();
        //3.添加元素
        ts.add(stu1);
        ts.add(stu2);
        ts.add(stu3);
        //4.打印集合
        System.out.println(ts);
    }
}
package com.zjut.TreeSet;
import java.util.Objects;
public class Student implements Comparable<Student>{
    private String name;
    private int age;
    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    //this:当前要添加的元素,
    //0:表示已经在红黑树中存在的元素
    //返回值:
    //负数:表示当前要添加的元素是小的,存红黑树的左边
    //正数:表示当前要添加的元素是大的,存红黑树的右边
    //0:表示当前要添加的元素已经存在,舍弃
    public int compareTo(Student o) {
        System.out.println("------------------");
        System.out.println("this:" + this);
        System.out.println("o:" + o);
        //指定排序规则
        //只看年龄:按照年龄的升序排列
        return  this.getAge() - o.getAge()  ;
    }
}
5.4.2 比较器排序

例子:
 TreeSet对象排序练习
 
package com.zjut.TreeSet;
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo3 {
    public static void main(String[] args) {
        /**
         * 需求:请自行选择比较器排序和自然排序两种方式:
         * 要求:存入四个字符串,“c" ,"ab", "df", "qwer"
         * 按照长度从短到长排序,如果长度一样则按照首字母排序。
         */
        //HashSet集合,字符串默认按照首字母排序,不会按照长度排序
        //1.创建集合 ,传递比较器 Comparator 比较规则
        TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
            @Override
            //s:要添加的元素
            //t1:表示已经在红黑树中存在的元素
            public int compare(String s, String t1) {
                int i = s.length() - t1.length();
                //如果一样,则按照默认的首字母排序
                i = i == 0 ? s.compareTo(t1) : i;
                return i;
            }
        });
/* 因为Comparator是函数式接口,所以可以使用 lambda 表达式写法
        TreeSet<String> ts = new TreeSet<>(( s,  t1) -> {
                int i = s.length() - t1.length();
                //如果一样,则按照默认的首字母排序
                i = i == 0 ? s.compareTo(t1) : i;
                return i;
        });
*/
        ts.add("c");
        ts.add("ab");
        ts.add("df");
        ts.add("qwer");
        System.out.println(ts);
    }
}
输出:
 ![[ab, c, df, qwer]](https://img-blog.csdnimg.cn/54c7a7d5d8f943178da2cd99b99a3380.png)
5.5. TreeSet对象排序练习

package com.zjut.TreeSet;
import java.util.TreeSet;
public class TreeSetDemo4 {
    public static void main(String[] args) {
        /*TreeSet排序规则
        * 1.默认排序,自然排序
        * 2.比较器排序
        * 默认情况下,用第一种排序,如果第一种不能满足当前的需求,采用第二种方式
        * */
         //1.创建学生对象
        Student02 st1 = new Student02("zhangsan",23,90,98,89);
        Student02 st2 = new Student02("lisi",24,91,97,88);
        Student02 st3 = new Student02("wangwu",25,90,96,70);
        Student02 st4 = new Student02("zhaoliu",26,60,80,68);
        Student02 st5 = new Student02("qianqi",27,70,77,77);
        //2.创建集合
        //默认选择ArrayList
        //HashSet
        //TreeSet
        TreeSet<Student02> ts = new TreeSet<>() ;
        ts.add(st1);
        ts.add(st2);
        ts.add(st3);
        ts.add(st4);
        ts.add(st5);
        //System.out.println(ts);
        for (Student02 t : ts) {
            System.out.println(t);
        }
    }
}
package com.zjut.TreeSet;
public class Student02 implements Comparable<Student02> {
    private String name;
    private int age;
    private int chinese;
    private int math;
    private int english;
    public Student02() {
    }
    public Student02(String name, int age, int chinese, int math, int english) {
        this.name = name;
        this.age = age;
        this.chinese = chinese;
        this.math = math;
        this.english = english;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getChinese() {
        return chinese;
    }
    public void setChinese(int chinese) {
        this.chinese = chinese;
    }
    public int getMath() {
        return math;
    }
    public void setMath(int math) {
        this.math = math;
    }
    public int getEnglish() {
        return english;
    }
    public void setEnglish(int english) {
        this.english = english;
    }
    @Override
    public String toString() {
        return "Student02{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", chinese=" + chinese +
                ", math=" + math +
                ", english=" + english +
                '}';
    }
    /*
     * 按照总分从高到底 输出到控制台
     * 如果总分一样,按照语文成绩排
     * 如果语文一样,按照数学成绩排
     * 如果数学成绩一样,按照英语成绩排
     * 如果英语成绩一样,按照年龄排
     * 如果年龄一样,按照姓名的首字母排
     * 如果都一样,认为是同一个学生,不存
     * */
    @Override
    public int compareTo(Student02 student02) {
        int sum1 = this.getChinese() + this.getEnglish() + this.getMath();
        int sum2 = student02.getChinese() + student02.getMath() + student02.getEnglish();
        //比较两者总分
        int i = sum1 - sum2;
        //如果总分一样,按照语文成绩排
        i = i == 0 ? this.getChinese() - student02.getChinese() : i;
        //如果语文一样,按照数学成绩排
        i = i == 0 ? this.getMath() - student02.getMath() : i;
        //如果数学成绩一样,按照英语成绩排,(可以省略,因为三门成绩总分一样,而语文,数学成绩一样,那英语成绩肯定一样)
        i = i == 0 ? this.getEnglish() - student02.getEnglish() : i;
        //如果英语成绩一样,按照年龄排
        i = i == 0 ? this.getAge() - student02.getAge() : i;
        //如果年龄一样,按照姓名的首字母排
        i = i == 0 ? this.getName().compareTo(student02.getName()): i;
        return i;
    }
}

5.6 TreeSet小结
5.6.1 TreeSet集合的特点?

5.6.2 TreeSet集合自定义排序规则有几种方式?

5.6.3 方法返回值得特点

6. 单列集合使用场景













![[python][vpython]用vpython实现小球砸弹簧代码](https://img-blog.csdnimg.cn/f339354c25964d1c990b16054819ee2d.jpeg)





