Java --> Set系列集合

 

 

  • HashSet、LinkedHashSet
 1     public static void main(String[] args) {
 2         //Set系列集合:HashSet、LinkedHashSet、TreeSet
 3         //多态写法
 4         //Set<String> sets = new HashSet<>(); //HashSet:无序、不重复、无索引
 5         Set<String> sets = new LinkedHashSet<>(); // LinkedHashSet:有序、不重复、无索引
 6         sets.add("Java");
 7         sets.add("C语言");
 8         sets.add("数据结构");
 9         sets.add("Java");
10         sets.add("HTML");
11         sets.add("CSS");
12         System.out.println(sets);
13     }

HashSet示例运行结果:

LinkedHashSet示例运行结果:

  •  相同对象的哈希值是一样的,不同对象的哈希值是不同的(对象的哈希值一旦确定,便不会改变,即与运行次数无关):

 

 

  

 

 

 可以看到,两次运行的结果是一样的。

  •  HashSet1.7版本原理解析:(数组+链表)

 

 

  •  JDK1.8之后开始HashSet原理解析:数组 + 链表 + 红黑树 ,众所周知,当JDK1.8之前,如上边的1.7而言,当多个元素的哈希值相等时,改地址的元素就会变成链表,而我们知道,一旦链表的长度过长,便会使得元素的删除和查询性能大大降低。当链表的长度大于8的时候,便会自动转换为红黑树。有关红黑树的具体知识大家可参考这篇文章,个人感觉算是介绍的非常详细的一篇了:
  • https://www.zhihu.com/question/312327402/answer/1263993419

 

 

  •  案例:Set集合去重复
  • 需求:创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历改集合,要求:学生对象的成员变量值相同,我们就认为时同一个对象。

实现步骤分析:

  1. 定义学生类,创建HashSet集合对象,创建学生对象;
  2. 把学生添加到集合中;
  3. 重点:在学生列中重写两个方法 -- hashCode()和equals(),自动生成即可;
  4. 遍历集合(增强for)。

学生类:

 1 public class Student {
 2     private String name;
 3     private int age;
 4     private char sex;
 5 
 6     @Override
 7     public String toString() {
 8         return "Student{" +
 9                 "name='" + name + '\'' +
10                 ", age=" + age +
11                 ", sex=" + sex +
12                 '}';
13     }
14 
15     @Override
16     public boolean equals(Object o) {
17         if (this == o) return true;
18         if (o == null || getClass() != o.getClass()) return false;
19         Student student = (Student) o;
20         return age == student.age && sex == student.sex && Objects.equals(name, student.name);
21     }
22 
23     @Override
24     public int hashCode() {
25         return Objects.hash(name, age, sex);
26     }
27 
28     public Student() {
29     }
30 
31     public Student(String name, int age, char sex) {
32         this.name = name;
33         this.age = age;
34         this.sex = sex;
35     }
36 
37     public String getName() {
38         return name;
39     }
40 
41     public void setName(String name) {
42         this.name = name;
43     }
44 
45     public int getAge() {
46         return age;
47     }
48 
49     public void setAge(int age) {
50         this.age = age;
51     }
52 
53     public char getSex() {
54         return sex;
55     }
56 
57     public void setSex(char sex) {
58         this.sex = sex;
59     }
60 }
 1 public static void main(String[] args) {
 2         //Set集合去重复原因:先判断哈希值,在判断equals
 3         Set<Student> stus = new HashSet<>();
 4         Student s1 = new Student("Jack",21,'');
 5         Student s2 = new Student("Jack",21,'');
 6         Student s3 = new Student("Rose",20,'');
 7 
 8         System.out.println(s1.hashCode());
 9         System.out.println(s2.hashCode());
10         System.out.println(s3.hashCode());
11 
12         stus.add(s1);
13         stus.add(s2);
14         stus.add(s3);
15 
16         System.out.println(stus);
17     }

示例运行结果:

 

 

 通过重写对象的hashCode和equals方法,可以实现Set集合中2个内容相同的对象就是重复的。

 

 

 示例运行结果:

 

 

 底层原理:基于哈希表,每个元素额外多了一个双链表的机制记录存储的顺序

 

 

  •  实现类:TreeSet
  • 不重复、无索引、可排序
  • 案例:TreeSet集合的比较规则(数值型、字符串型、以及自定义类型):

Cat类:

 1 public class Cat implements Comparable<Cat>{ //实现Comparable接口,重写compareTo方法可实现自定义比较规则
 2     private String name;
 3     private String color;
 4     private int age;
 5     private double weight;
 6 
 7     //类自定义比较规则
 8     @Override
 9     public int compareTo(Cat o) {
10         return this.age - o.age; //年龄升序(反之年龄降序)
11         //return (this.age - o.age >= 0) ? 1 : -1; //保留相同对象
12         //return Double.compare(this.weight,o.weight); //体重升序(反之体重降序)
13         //return (this.weight - o.weight >= 0) ? 1 : -1; //保留相同对象
14     }
15 
16     @Override
17     public String toString() {
18         return "Cat{" +
19                 "name='" + name + '\'' +
20                 ", color='" + color + '\'' +
21                 ", age=" + age +
22                 ", weight=" + weight +
23                 '}';
24     }
25 
26     public Cat() {
27     }
28 
29     public Cat(String name, String color, int age, double weight) {
30         this.name = name;
31         this.color = color;
32         this.age = age;
33         this.weight = weight;
34     }
35 
36     public String getName() {
37         return name;
38     }
39 
40     public void setName(String name) {
41         this.name = name;
42     }
43 
44     public String getColor() {
45         return color;
46     }
47 
48     public void setColor(String color) {
49         this.color = color;
50     }
51 
52     public int getAge() {
53         return age;
54     }
55 
56     public void setAge(int age) {
57         this.age = age;
58     }
59 
60     public double getWeight() {
61         return weight;
62     }
63 
64     public void setWeight(double weight) {
65         this.weight = weight;
66     }
67 }
 1 public static void main(String[] args) {
 2         System.out.println("-----------数值型-------------");
 3         Set<Integer> sets = new TreeSet<>(); //不重复、无索引、可排序
 4         sets.add(18);
 5         sets.add(19);
 6         sets.add(21);
 7         sets.add(5);
 8         System.out.println(sets);
 9 
10         System.out.println("-------------字符串型(ASCII)--------------");
11         Set<String> sets2 = new TreeSet<>();
12         sets2.add("Java");
13         sets2.add("HTML");
14         sets2.add("CSS");
15         sets2.add("MySQL");
16         sets2.add("HTML");
17         sets2.add("java");
18         sets2.add("");
19         System.out.println(sets2);
20 
21         System.out.println("------------自定义比较规则-------------");
22         Set<Cat> cats = new TreeSet<>();
23         cats.add(new Cat("大橘猫","橘色",2,2.5));
24         cats.add(new Cat("狸花猫","狸色",1,1.5));
25         cats.add(new Cat("小黑","黑色",3,3.5));
26         cats.add(new Cat("小黑","黑色",3,3.5));
27         System.out.println(cats);
28     }

示例运行结果:

 

 

 

 

 

 以上便是在类中实现Comparable接口,在类中重写comparaTo方法的方式实现了TreeSet集合的自定义排序。

  • 方式二:TreeSet集合自带比较器对象进行规则定制

 

 

 

 

 可以看到:集合内部的比较器会优先使用。还可以使用Lambda表达式简化函数式接口的匿名内部类:

 

 

 


对此,我们对Collection体系的集合做一个简答的总结:

  1. 如果希望元素可以重复,又有索引,索引查询快时可用ArrayList集合,因为它时基于数组的。(用的最多);
  2. 如果希望元素可以重复,又有索引,增删首位操作快则可以使用LinkedList集合,基于链表;
  3. 如果希望增删改查相对都较快,但是元素不重复、无序、无索引,可以使用HashSet,基于哈希表
  4. 如果希望增删改查都快,但是元素不重复、有序、无索引,可以使用LinkedHashSet,基于哈希表和双链表;
  5. 如果希望对对象进行排序,可以使用TreeSet集合,基于红黑树。后续也可以使用List集合进行排序。

 

posted @ 2022-05-15 19:48  羽梦齐飞  阅读(51)  评论(0编辑  收藏  举报