首页 > 编程语言 >Java中的Set系列集合超详解

Java中的Set系列集合超详解

时间:2024-07-13 13:29:31浏览次数:20  
标签:tmp Set Java add 详解 Student new public TreeSet

 Set

 List是有序集合的根接口,Set是无序集合的根接口,无序也就意味着元素不重复。更严格地说,Set集合不包含一对元素e1和e2 ,使得e1.equals(e2) ,并且最多一个空元素。
  使用Set存储的特点与List相反:元素无序、不可重复。常用的实现方式:HashSet、LinkedHashSet和TreeSet。

Set系列集合概述和特点

  • 底层数据结构是哈希表

  • 存取无序

  • 不可以存储重复元素

  • 没有索引,不能使用普通for循环遍历

set集合的基本应用

 public static void main(String[] args) {
        Set<String> s=new HashSet<String>();
        boolean flag1= s.add("aaa");
        boolean flag2 = s.add("aaa");
        System.out.println(flag1);
        System.out.println(flag2);
        System.out.println(s);
        //如果当前元素是第一次添加,那么可以添加成功,返回true
        //如果当前元素是第二次添加,那么添加失败,返回false

    }

        

存储字符串并遍历

方式一迭代器方式

 public static void main(String[] args) {
        Set<String> s=new HashSet<String>();
        s.add("张三");
        s.add("李四");
        //迭代器
        Iterator<String> it = s.iterator();
        while(it.hasNext()){
            String str = it.next();
            System.out.println(str);
        }


    }

方式2-增强for


        //增强for
        for (String str : s) {
            System.out.println(str);
        }

方式3lambda表达式

 // Lambda表达式
        s.forEach((String str)-> System.out.println(str));

总结

HashSet集合概述和特点

  • 底层数据结构是哈希表

  • 存取无序

  • 不可以存储重复元素

  • 没有索引,不能使用普通for循环遍历

哈希值

  • 哈希值简介

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

  • 如何获取哈希值

    Object类中的public int hashCode():返回对象的哈希码值

  • 哈希值的特点

    • 同一个对象多次调用hashCode()方法返回的哈希值是相同的

    • 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同

package set;
/*
           哈希值:
               对象的整数表现形式
               1. 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
               2. 如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
               3. 但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)

        */
public class demo3 {
    public static void main(String[] args) {

        //   1. 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
        Student s1 = new Student("zhangsan",18);
        Student s2 = new Student("zhangsan",18);
      /*  System.out.println(s1.hashCode());//189568618
        System.out.println(s2.hashCode());//793589513*/
        //不一样,所以我们要重写hashCode()
        //  2. 如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样
        System.out.println("------------------");
        System.out.println(s1.hashCode());//1461067297
        System.out.println(s2.hashCode());//1461067297

       // 3. 但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)
        //哈希碰撞
        System.out.println("abc".hashCode());//96354
        System.out.println("acD".hashCode());//96354
    }
}

练习

package lx;

import java.util.HashSet;

public class demo1 {
    public static void main(String[] args) {
        Student s1 = new Student("张三", 8);
        Student s2 = new Student("张三", 8);
        Student s3 = new Student("李四", 18);
        Student s4 = new Student("王五", 17);
        HashSet<Student> set = new HashSet<Student>();
        set.add(s1);
        set.add(s2);
        set.add(s3);
        set.add(s4);
        //重写hashCode方法就可以去重复的对象
        //因为重写hashCode方法,比的是属性值,属性值一样,哈希值一样,所以添加不成功
        //不重写比的是地址值,创建出来的对象地址值永远不一样,所以哈希值不一样,所以添加成功
        //如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样
        //重写equals方法也一样 比的也是地址值,不是属性值
        for (Student student : set) {

            System.out.println(student);
        }


    }
}

注意像String Integer类型的,Java已经在底层重写好了HashSet和equals方法

LinkedHashSet

package LinkedHashSet;

import lx.Student;


import java.util.HashSet;
import java.util.LinkedHashSet;

public class demo1 {
    public static void main(String[] args) {

        Student s1 = new Student("张三", 8);


        Student s2 = new Student("张三", 8);
        Student s3 = new Student("李四", 18);
        Student s4 = new Student("王五", 17);
        LinkedHashSet<Student> set = new LinkedHashSet<Student>();
        set.add(s3);
        set.add(s1);
        set.add(s3);
        set.add(s4);
        //LinkedHashSet的存和去顺序一样
        for (Student student : set) {

            System.out.println(student);
        }

    }
}

 

TreeSet

package TreeSet;

import java.util.TreeSet;

public class demo1 {
    public static void main(String[] args) {
        //利用TreeSet对整数进行排序
        //默认升序
        TreeSet<Integer> ts = new TreeSet<>();
        //添加元素
        ts.add(4);
        ts.add(2);
        ts.add(5);
        ts.add(8);
        ts.add(1);
        //使用增强for
        for (Integer t : ts) {
            System.out.print(t + " ");
        }

    }
}

package TreeSet;

import java.util.TreeSet;

public class demo2 {
    public static void main(String[] args) {
        //利用TreeSet对String类型进行排序
        TreeSet<String> ts = new TreeSet<>();
        ts.add("va");
        ts.add("aaa");
        ts.add("ha");
        ts.add("aba");
        ts.add("acd");
        for (String t : ts) {
            System.out.print(t + " ");
        }
    }
}

练习

 @Override
    public int compareTo(Student o) {
        //只看年龄按照升序排序
       int tmp=this.getAge() - o.getAge();
      tmp= tmp==0?this.getName().compareTo(o.getName()):tmp;
      return tmp;
    }
package TreeSet;

import javax.print.DocFlavor;
import java.util.TreeSet;
import java.util.function.Consumer;

public class demo3 {
    public static void main(String[] args) {
        //利用TreeSet对学生类型进行排序
        TreeSet<Student> ts = new TreeSet<>();
        //要求: 按照学生的年龄进行排序
        //同年按照姓名字母排序
        //同姓名,同年龄认为同一个人
        Student s1 = new Student("zhangsan", 18);
        Student s2 = new Student("lisi", 19);
        Student s3 = new Student("wangwu", 19);

        ts.add(s2);
        ts.add(s3);
        ts.add(s1);
        System.out.println(ts);
        //方式一:默认的排序方式,Student实现一个接口(comparable接口)重写里面的抽象方法
        //再指定比较规则



        //hashCode和equals方法跟哈希表有关
        //TreeSet底层红黑树有关
        //所以不需要重写hashCode和equals方法
    }
}

package TreeSet;

import java.util.Comparator;
import java.util.TreeSet;

public class demo4 {
    public static void main(String[] args) {
        //方法二:比较器排序
        //1.创建集合
        //2.o1表示当前要添加的元素
        //3.o2表示已经在红黑树存在的元素
        //返回值规则跟之前一样
        TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
            @Override
            /*
            需求:请自行选择比较器排序和自然排序两种方式;
            要求:存入四个字符串, “c”, “ab”, “df”, “qwer”
            按照长度排序,如果一样长则按照首字母排序

            采取第二种排序方式:比较器排序
             */
            public int compare(String o1, String o2) {
                //按照长度来
                int tmp = o1.length() - o2.length();
                //如果一样长则按照首字母排序
                    tmp = tmp == 0 ? o1.compareTo(o2) : tmp;
                return tmp;
            }
        });
        //2.添加元素
        ts.add("c");
        ts.add("ab");
        ts.add("df");
        ts.add("qwer");
        System.out.println(ts);
    }
}

package lx2;

import java.util.TreeSet;

/*  需求:创建5个学生对象
        属性:(姓名,年龄,语文成绩,数学成绩,英语成绩),
        按照总分从高到低输出到控制台
        如果总分一样,按照语文成绩排
        如果语文一样,按照数学成绩排
        如果数学成绩一样,按照英语成绩排
        如果英文成绩一样,按照年龄排
        如果年龄一样,按照姓名的字母顺序排
        如果都一样,认为是同一个学生,不存。

        第一种:默认排序/自然排序
        第二种:比较器排序

        默认情况下,用第一种排序方式,如果第一种不能满足当前的需求,采取第二种方式。


        课堂练习:
            要求:在遍历集合的时候,我想看到总分。

      */
public class demo1 {
    public static void main(String[] args) {
        //1.创建学生对象
        Student s1 = new Student("zhangsan", 23, 90, 99, 50);
        Student s2 = new Student("lisi", 24, 90, 98, 50);
        Student s3 = new Student("wangwu", 25, 95, 100, 30);
        Student s4 = new Student("zhaoliu", 26, 60, 99, 70);
        Student s5 = new Student("qianqi", 26, 70, 80, 70);
        TreeSet<Student> st=new TreeSet<>();
        st.add(s1);
        st.add(s2);
        st.add(s3);
        st.add(s4);
        st.add(s5);
        for (Student student : st) {
            System.out.println(student);
        }

    }
}

package lx2;

//第一种:默认排序/自然排序
public class Student implements Comparable<Student> {
    private String name;
    private int age;
    //语文成绩
    private int chinese;
    //数学成绩
    private int math;
    //英语成绩
    private int english;

    public Student() {
    }

    public Student(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;
    }

    /**
     * 获取
     *
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     *
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     *
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     *
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    /**
     * 获取
     *
     * @return chinese
     */
    public int getChinese() {
        return chinese;
    }

    /**
     * 设置
     *
     * @param chinese
     */
    public void setChinese(int chinese) {
        this.chinese = chinese;
    }

    /**
     * 获取
     *
     * @return math
     */
    public int getMath() {
        return math;
    }

    /**
     * 设置
     *
     * @param math
     */
    public void setMath(int math) {
        this.math = math;
    }

    /**
     * 获取
     *
     * @return english
     */
    public int getEnglish() {
        return english;
    }

    /**
     * 设置
     *
     * @param english
     */
    public void setEnglish(int english) {
        this.english = english;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + ", chinese = " + chinese + ", math = " + math + ", english = " + english + "}";
    }

    @Override
    public int compareTo(Student o) {
       /* 按照总分从高到低输出到控制台
        如果总分一样,按照语文成绩排
        如果语文一样,按照数学成绩排
        如果数学成绩一样,按照英语成绩排
        如果英文成绩一样,按照年龄排
        如果年龄一样,按照姓名的字母顺序排
        如果都一样,认为是同一个学生,不存。*/
        int sum1 = this.getChinese() + this.getMath() + this.getEnglish();
        int sum2=o.getChinese() + o.getMath() + o.getEnglish();
        int tmp = sum2-sum1;
        // 如果总分一样,按照语文成绩排
        tmp = tmp == 0 ? this.getChinese() - o.getChinese() : tmp;
        // 如果语文一样,按照数学成绩排
        tmp = tmp == 0 ? this.getMath() - o.getMath() : tmp;
        //如果数学成绩一样,按照英语成绩排
        tmp = tmp == 0 ? this.getEnglish() - o.getEnglish() : tmp;
        //如果英文成绩一样,按照年龄排
        tmp = tmp == 0 ? this.getAge() - o.getAge() : tmp;
        // 如果年龄一样,按照姓名的字母顺序排
        tmp = tmp == 0 ? this.getName().compareTo(o.getName()) : tmp;


        return tmp;
    }
}

TreeSet二种排序方式



总结

标签:tmp,Set,Java,add,详解,Student,new,public,TreeSet
From: https://blog.csdn.net/weixin_65752158/article/details/140354550

相关文章

  • JAVA初级之IO流
    目录1、概述1.1什么是IO1.2IO的分类1.3IO的流向说明图解1.4IO流的父类2、字节流2.1字节流概念2.2字节输出流【OutputStream】2.2.1字节输出流的基本方法 2.2.2 FileOutputStream类2.2.3写出字节数据2.2.3数据追加续写 2.2.4写出换行 2.3 字节输入......
  • 13-TreeSet和TreeMap基本介绍
    13-TreeSet和TreeMap基本介绍介绍汇总:TreeSet基本介绍TreeMap基本介绍1-TreeSet基本介绍TreeSet类用于存储一组对象,并将对象按照自然规则(实现Comparator接口的)或者指定Comparator对象的比较器进行排序。TreeSet类中的底层是TreeMap。key值不可以为null,也不......
  • 学生Java学习路程-2
    ok,到了一周一次的总结时刻,我大致会有下面几个方面的论述:1.这周学习了Java的那些东西2.这周遇到了什么苦难3.未来是否需要改进方法等几个方面阐述我的学习路程。这周主要通过网上找的一些课程来学习java,因为直接看项目它用的语句根本不知道什么意思,简直是一脸懵逼,但因为找的是零基......
  • Java集合之Collection集合详解
    目录Collection集合 List接口ArrayList集合LinkedList集合List集合遍历Iterator迭代器增强for循环forEach遍历集合Set接口HashSet集合TreeSet集合Collection集合 Collection集合最基本的集合接口,用于存储一系列元素。Collection集合有两个重要的子接口,分别......
  • Java代码初始化块
    目录实例域代码块静态域代码块初始化代码块分为静态域代码块和实例域代码块,静态域代码块在类第一次被加载时被执行,实例域代码块在创建对象时被执行,一个类中可以有多个代码块。 实例域代码块使用方法可以有输出语句可以对类的属性、类的声明进行初始化操作对集......
  • [0071]基于JAVA的上门服务费用智慧管理系统的设计与实现
    毕业设计(论文)开题报告表姓名学院专业班级题目基于JAVA的上门服务费用智慧管理系统的设计与实现指导老师(一)选题的背景和意义随着社会的发展,越来越多的服务行业开始注重服务质量和服务效率的提升,以满足消费者日益增长的需求。而上门服务作为一种方便......
  • [0074]基于JAVA的专利信息智慧管理系统的设计与实现
    毕业设计(论文)开题报告表姓名学院专业班级题目基于JAVA的专利信息智慧管理系统的设计与实现指导老师(一)选题的背景和意义在当今社会,知识产权保护越来越受到重视,专利作为知识产权的重要组成部分,其管理对于企业的创新能力和市场竞争力具有重要影响。然......
  • [0073]基于JAVA的专业娱乐器材租赁智慧管理系统的设计与实现
    毕业设计(论文)开题报告表姓名学院专业班级题目基于JAVA的专业娱乐器材租赁智慧管理系统的设计与实现指导老师(一)选题的背景和意义随着科技的发展,越来越多的人开始追求高品质的生活,娱乐器材的需求也在不断增加。然而,传统的娱乐器材租赁方式存在诸多问......
  • [Java]面试官:你对异常处理了解多少,例如,finally中可以有return吗?
    【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)https://www.cnblogs.com/cnb-yuchen/p/18299911出自【进步*于辰的博客】参考笔记一,P35.4/5。目录1、介绍2、try...with...resources最后1、介绍相信大家对try...catch...finally都很熟悉了,在此我提一点使用细......
  • java线程池的一个小坑:shutdown之后线程并不会停止运行
    问题背景最近我想要实现一个这样的功能:在线程运行超过一段时间之后就向主程序抛出一个异常,并停止这个线程。其具体的应用场景是一个任务由多个子任务组成,每个子任务单独一个线程,如果某个子任务长时间未完成就认为这个子任务失败(可能是因为网络原因卡死了),就需要把这个线程结束掉,......