Set

Set

  • set系列集合特点

    • 无序,不重复,无索引
    • set集合的方法基本上和collectio的API一样
  • Set集合的实现类特点

    • HasSet:无序,不重复,无索引
    • LinkedHashSet:有序,不重复,无索引
    • TreeSet:可排序,不重复,无索引
  • HashSet底层原理

    • 底层原理详解:

      1.创建一个默认长度16,默认加载因子为0.75(这个意思是当16*0.75的数组被填满时,这是数组就要扩容为原先的两倍)的数组,数组名为table

      2.根据元素的哈希值跟数组的长度计算出英存入的位置

      3.判断当前位置是否为null,是的话直接存入

      4.不是,则表示有元素。则调用equals方法比较属性值:

      • 属性值一样,则不存
      • 不一样则存入数组,形成链表
      • jdk8以前,新元素存入数组,老元素挂在新元素下面
      • jdk8以后呢,新元素直接挂在老元素下面
      • jdk8以后,当链表长度大于8,且数组长度大于等于64时,自动转为红黑树
    • HashSet集合底层采取哈希表存储数据

    • 哈希表是一种对于增删改查数据性能都有比较好的结构

    • 哈希表组成:

      • jdk8之前:数组加链表
      • jdk8之后:数组+链表+红黑树
  • 哈希值:

    • 根据HashCode方法算出来的int类型的整数
    • 该方法定义在object类中,所有对象都可以调用,默认使用地址值继续计算
    • 一般情况下,会重写hashcode方法,利用对象内部的属性值计算哈希值
  • 对象的哈希值特点

    • 如果没有重写hashcode方法,不同对象计算出的哈希值是不同的

    • 如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的

      package A01Set;
      
      public class HashSetDemo01 {
          public static void main(String[] args) {
              /*
      
              哈希值:
                  对象的整数表现形式
                  1.如果没有重写hashcode方法,不同对象算出的哈希值是不同的
                  2.如果已经重写hashcode方法,不同的对象只要属性值想相同,计算出的哈希值就是一样的
                  3.但是在小部分情况下,不同的属性值或不同的地址值计算出来的哈希值可一样,这叫哈希碰撞
      
               */
      
              //1.创建对象
              Student s1=new Student("zhangsan",23);
              Student s2=new Student("zhangsan",23);
      
              //2.
              System.out.println(s1.hashCode());
              System.out.println(s2.hashCode());
      
      
              System.out.println("abc".hashCode());
              System.out.println("acD".hashCode());
          }
      }
      
      
      • 封装

        package A01Set;
        
        import java.util.Objects;
        
        public class Student {
            private String name;
            private  int age;
        
            public Student(){}
        
            public void setName(String name) {
                this.name = name;
            }
        
            public Student(String name,int age){
                this.name=name;
                this.age=age;
            }
        
            public String getName() {
                return name;
            }
        
        
            public int getAge() {
                return age;
            }
        
            public void setAge(int age) {
                this.age = age;
            }
        
            @Override
            public boolean equals(Object o) {
                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 +
                        '}';
            }
        
        
        }
        

        1.为什么hashset的存取顺序不一样

        答:因为取的时候为从数组的0索引开始一个个检阅,当某个数组位置有链表时,再一个一个读取链表里的东西,而存放的时候是要根据hashcode方法算出哈希值存入的,不是按照索引的方式

        2.HashSet为什么没有索引

        答:因为HashSet不够纯粹,它是由数组+链表+加红黑树构成的,所以数组有索引的地方且有链表,但一个数组索引不能够代表链表里所有的对象,所以没有索引

        3.HashSet是利用什么机制保证数据去重的

        答:1.hashcode方法计算哈希值,哈希值确定当前元素存储位置

        ​ 2.equals方法,对比内部的属性值是否相同

        ​ 3.如果存入的是自定义对象,那一定要重写这俩个方法

package A01Set;

import java.util.HashSet;
/*
需求:创建一个存储学生对象的集合,存储多个学生对象
使用程序实现在控制台遍历该集合
要求:学生对象的成员变量值相同,我们就认为是一个对象*/
public class HashDemo02 {
    public static void main(String[] args) {
        //1.创建对象
        Student s1=new Student("zhangsan",23);
        Student s2=new Student("lisi",24);
        Student s3=new Student("wangwu",25);
        Student s4=new Student("zhangsan",23);


        //2.创建集合添加学生
        HashSet<Student> ha=new HashSet<>();

        //3.添加元素
        System.out.println(ha.add(s1));
        System.out.println(ha.add(s2));
        System.out.println(ha.add(s3));
        System.out.println(ha.add(s4));

        //4.打印集合
        System.out.println(ha);
    }
}

  • LinkedHashSet底层原理

    • 有序,不重复,无索引

    • 底层数据结构依然是哈希表,只是每个元素有额外的多了一个双链表的机制记录存储的顺序

      package A01Set;
      
      import java.util.LinkedHashSet;
      
      public class LinkeHashset {
          public static void main(String[] args) {
              //1.创建对象
              Student s1=new Student("zhangsan",23);
              Student s2=new Student("lisi",24);
              Student s3=new Student("wangwu",25);
              Student s4=new Student("zhangsan",23);
      
              //2.创建集合
              LinkedHashSet<Student> lh=new LinkedHashSet<>();
      
              //3.添加元素
              System.out.println(lh.add(s1));
              System.out.println(lh.add(s2));
              System.out.println(lh.add(s3));
              System.out.println(lh.add(s4));
      
              //4.打印集合
              System.out.println(lh);
      
      • 以后要数据去重,使用哪个

        默认使用hashSet

        如果有要求去重且有序,才使用LinkedHashSet

  • TreeSet(底层是红黑树)

    • 不重复,无索引,可排序

    • 可排序:按照元素的默认规则(由小到大)排序

    • TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都比较好

    • TreeSet集合默认的规则:

      • 对于数值类型1:integer,double默认按照从小到大的顺序进排序
      • 对于字符字符串类型:按照字符在ASCii码表中数字升序进行排序
    • TreeSet的两种比较方式

      • 方式一:默认排序/自然排序:Javabean类实现Comparable接口指定比较规则

      •     public int compareTo(Student o) {
                System.out.println("--------------------");
                System.out.println("this:"+this);
                System.out.println("o"+o);
        
        
                //指定排序的规则
                //只看年龄,我想要按照年龄的升序进行排列
                return this.getAge()-o.getAge();
            }
        
      • package A01Set;
        
        import org.w3c.dom.ls.LSOutput;
        
        import java.util.TreeSet;
        
        public class TreeSetDemo02 {
            //自定义类使用treeset,该如何比较的问题
            public static void main(String[] args) {
        
        
                //1.创建三个学生对象
                Student s1 = new Student("zhangsan", 23);
                Student s2 = new Student("lisi", 24);
                Student s3 = new Student("wangwu", 25);
        
                //2,创建集合对象
                TreeSet<Student> ts = new TreeSet<>();
        
                //3.添加元素
                ts.add(s3);
                ts.add(s2);
                ts.add(s1);
        
                //4.打印集合
                System.out.println(ts);
        
                //TreeSet底层是红黑树
            }
        }
        
      • 方式二:比较器排序,

package A01Set;

public class Student2 implements Comparable<Student2> {
    private  String name;
    private  int age;
    private  int Chinese;
    private  int Math;
    private  int English;

    public Student2(){}

    public Student2(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) {
        Chinese = chinese;
    }

    public int getMath() {
        return Math;
    }

    public void setMath(int math) {
        Math = math;
    }

    public int getEnglish() {
        return English;
    }

    public void setEnglish(int english) {
        English = english;
    }

    @Override
    public String toString() {
        return "Student2{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", Chinese=" + Chinese +
                ", Math=" + Math +
                ", English=" + English +
                '}';
    }


    @Override
    public int compareTo(Student2 o) {
        int sum1=this.getChinese()+this.getMath()+this.getEnglish();
        int sum2=o.getChinese()+o.getMath()+o.getEnglish();

        int i=sum1-sum2;
        i=i==0?this.getChinese()-o.getChinese():i;
        i=i==0?this.getMath()-o.getMath():i;
        i=i==0?this.getEnglish()- o.getEnglish():i;

        i=i==0?this.getAge()-o.getAge():i;

        return i;


    }
}

package A01Set;

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

public class TreeSetDemo03 {
    public static void main(String[] args) {
        /**
         * 需求:请自行选择比较器排序和自然排序两种方式
         * 要求:存入四个字符”c“,”ab“,”df“,QWER
         * 按照长度排序,如果一样则按照首字符排序
         *
         * 采取第二种排序方式:比较器排序
         *
         */

        //1.创建集合对象
        TreeSet<String> ts=new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                int i=o1.length()-o2.length();
                i=i==0?o1.compareTo(o2):i;
                return i;
            }
        });


        //2.添加元素
        ts.add("c");
        ts.add("ab");
        ts.add("df");
        ts.add("qwer");

        //3.打印集合

        System.out.println(ts);
    }
}



package A01Set;

import java.util.TreeSet;
//实际问题练习
public class TreeSetDemo04 {
    public static void main(String[] args) {
        /*
        *按照总分从高到低输出到控制台
        * 如果总分一样,按照语文排序
        * 如果语文一样,按照数学排序
        * 如果数学一样,按照英语排序
        * 如果都一样,按照年龄排序
        * 如果都一样,则认为是一个学生,不存
        *

         */

        //1.创建对象
        Student2 s1=new Student2("zhangsan",23,90,99,50);
        Student2 s2=new Student2("lisi",24,90,98,50);
        Student2 s3=new Student2("wangwu",25,95,100,30);
        Student2 s4=new Student2("zhaoliu",26,60,99,70);
        Student2 s5=new Student2("zhangsan",27,70,80,70);

        //2.创建集合
        TreeSet<Student2> ts=new TreeSet<>();

        //3.添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);

        //4.打印集合
        for (Student2 t : ts) {
            Systym.out.println(t);
        }
    }
}

  • 方法返回值的特点:

    • 负数:表示当前要添加的元素是小的,存左边

    • 正数

      package A01Set;
      
      import java.util.TreeSet;
      
      public class TreeSetDemo04 {
          public static void main(String[] args) {
              /*
              *按照总分从高到低输出到控制台
              * 如果总分一样,按照语文排序
              * 如果语文一样,按照数学排序
              * 如果数学一样,按照英语排序
              * 如果都一样,按照年龄排序
              * 如果都一样,则认为是一个学生,不存
              *
      
               */
      
              //1.创建对象
              Student2 s1=new Student2("zhangsan",23,90,99,50);
              Student2 s2=new Student2("lisi",24,90,98,50);
              Student2 s3=new Student2("wangwu",25,95,100,30);
              Student2 s4=new Student2("zhaoliu",26,60,99,70);
              Student2 s5=new Student2("zhangsan",27,70,80,70);
      
              //2.创建集合
              TreeSet<Student2> ts=new TreeSet<>();
      
              //3.添加元素
              ts.add(s1);
              ts.add(s2);
              ts.add(s3);
              ts.add(s4);
              ts.add(s5);
      
              //4.打印集合
              for (Student2 t : ts) {
                  System.out.println(t);
              }
          }
      }
      
  • 方法返回值的特点:

    • 负数:表示当前要添加的值是小的,存左边
    • 整数:表示当前要添加的元素是大的,存右边
    • o🚴表示当前要添加的元素已经存在,舍弃

1.如果想要集合中的元素可重复

  • 用ArrayList集合,基于数组的(用的最多

2.如果想要集合中的元素可重复,而且当前的增删操作明显多于查询

  • 用LinkedList集合,基于链表

3.如果想对集合中的元素去重

  • 用Hash Set集合,基于哈希表的

4.如果想对集合中的元素去重,且保证存取顺序

  • 用LinkedHashSet集合,基于哈希表和双链表,效率低于HashSet

5.如果相对集合中的元素进行排序

  • 用TreeSet集合,基于红黑树,后续也可以用List集合实现排序

Map

  • Map接口特点

    • 用于存储任意键对值(key—vAlue)
    • 键:无序,无下标,不允许重复
    • 值:无序,无下标,可重复
  • Map父接口:存储一对数据,无序,无下标,键不可重复,值可重复

  • package A01Set;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    public class MapDemo01 {
        public static void main(String[] args) {
    
    
            //1.创建一个Map集合
            Map<String,String> ma=new HashMap<>();
    
            //2.添加元素
            ma.put("cn","中国");
            ma.put("uk","英国");
            ma.put("usa","美国");
            System.out.println("元素个数:"+ma.size());
            System.out.println(ma.toString());
    
    
            //3.删除
            //ma.remove("usa");
            //System.out.println(ma);
    
            //4.遍历
            //3.1使用KeySet()
            System.out.println("----------keyset()-----------");
            Set<String> keyset=ma.keySet();
            for (String key : keyset) {
                System.out.println(key+"--------"+ma.get(key));
            }
    
            //3.2使用entrySet
            Set<Map.Entry<String,String>> entries=ma.entrySet();
            for (Map.Entry<String, String> entry : entries) {
                System.out.println(entry.getKey()+"------"+entry.getValue());
            }
        }
    }
    
  • hashmap

    • package A01Set;
      
      import java.util.HashMap;
      import java.util.Map;
      
      public class HashMapDemo01 {
          public static void main(String[] args) {
              /*
              HashMap集合的使用
              存储结构:哈希表(链表加红黑树
               */
      
              //1.创建集合
              HashMap<Student3,String> ha=new HashMap<Student3,String>();
      
              //2.创建对象
              Student3 s1=new Student3("孙悟空",100);
              Student3 s2=new Student3("孙悟能",101);
              Student3 s3=new Student3("孙悟静",102);
              //3.添加val值
              ha.put(s1,"齐天大圣");
              ha.put(s2,"天蓬元帅");
              ha.put(s3,"大进军");
      
              //4.打印
              System.out.println("元素个数"+ha.size());
              System.out.println(ha.toString());
      
      
              //5.遍历
              for (Student3 key : ha.keySet()) {
                  System.out.println(key.toString()+"--------"+ha.get(key));
              }
      
      
              //entryset
              for (Map.Entry<Student3, String> entries : ha.entrySet()) {
                  System.out.println(entries.getKey()+"----"+entries.getValue());
              }
      
      
              //4.判断
              System.out.println(ha.containsKey(s1));
      
          }
      }
      
      
    • package A01Set;
      
      import java.util.Objects;
      
      public class Student3 {
          private String name;
          private int stuNo;
      
          public Student3(String name,int stuNo) {
              this.name = name;
              this.stuNo=stuNo;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getStuNo() {
              return stuNo;
          }
      
          public void setStuNo(int stuNo) {
              this.stuNo = stuNo;
          }
      
          @Override
          public boolean equals(Object o) {
              if (o == null || getClass() != o.getClass()) return false;
              Student3 student3 = (Student3) o;
              return stuNo == student3.stuNo && Objects.equals(name, student3.name);
          }
      
          @Override
          public int hashCode() {
              return Objects.hash(name, stuNo);
          }
      
          @Override
          public String toString() {
              return "A01Set.Student3{" +
                      "name='" + name + '\'' +
                      ", stuNo=" + stuNo +
                      '}';
          }
      }
      
      

Collections工具类

package A01Set;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CollectionsDemo01 {
    public static void main(String[] args) {
        //1.创建集合
        List<Integer> list=new ArrayList<>();

        //2.添加元素
        list.add(20);
        list.add(5);
        list.add(16);
        list.add(8);

        //3.sort排序
        System.out.println("排序之前:"+list.toString());
        Collections.sort(list);
        System.out.println("排序之后:"+list.toString());

        //4.二分查找
        int i=Collections.binarySearch(list,5);
        System.out.println(i);

        //copy
        List<Integer> dest=new ArrayList<>();
        for(int k=0;k<list.size();k++){
            dest.add(0);
        }
        Collections.copy(dest,list);
        System.out.println(dest.toString());

        //反转reverse
        Collections.reverse(list);
        System.out.println("反转之后"+list.toString());

        //打乱shuffle
        Collections.shuffle(list);
        System.out.println("大乱之后"+list.toString());


    }
}

posted @ 2025-11-18 13:44  RIcard  阅读(3)  评论(0)    收藏  举报