欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Set集合

程序员文章站 2022-04-15 14:37:24
...

  在Collection集合中List集合中的元素有序且允许重复,而Set集合中元素是唯一的,下面为大家介绍几种Set集合。

1、HashSet集合

  HashSet集合中元素的存取是无序的,且元素是唯一的。它的底层数据结构是哈希表,具有链表和数组的特点。
  HashSet集合靠着重写 hashCode() 和 equals() 方法来实现元素的唯一,如果不重写则不能保证元素的唯一性。

public class SetDemo {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("小明");
        set.add("小明");
        set.add("小红");
        set.add("小红");
        set.add("小李");
        set.add("小李");
        for (String s : set) {
            System.out.println(s);
        }
    }
}

//运行结果为:
小明
小李
小红

  由上面的代码可见,当元素重复存储的时候,在输出的时候元素就只有一个,重复的元素没有被存储(因为String类中已经重写过了方法)。如果我们存储的是自定义类的时候需要我们手动重写 hashCode() 和 equals() 方法来保证元素的唯一性。但是在重写的时候我们需要合理的进行重写,尽量减少碰撞。代码实现如下:
Student类

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 String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", 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);
    }
}

Test类

import java.util.HashSet;
public class MyTest {
    public static void main(String[] args) {
        Student s1 = new Student("王五", 25);
        Student s2 = new Student("王五", 25);
        Student s3 = new Student("王五", 25);
        Student s4 = new Student("王五", 252);
        Student s5 = new Student("王五2", 235);
        Student s6 = new Student("王五3", 25);
        Student s7 = new Student("王五4", 2665);
        Student s8 = new Student("王五5", 285);
        Student s9 = new Student("王五6", 285);
        Student s10 = new Student("王五7", 255);
        HashSet<Student> hashSet = new HashSet<>();
        hashSet.add(s1);
        hashSet.add(s2);
        hashSet.add(s3);
        hashSet.add(s4);
        hashSet.add(s5);
        hashSet.add(s6);
        hashSet.add(s7);
        hashSet.add(s8);
        hashSet.add(s9);
        hashSet.add(s10);
        for (Student student : hashSet) {
            System.out.println(student.getName() + "==" + student.getAge());
        }
    }
}

  上面的测试类的代码中HashSet集合中存储的为学生类,如果不手动重写 hashCode() 和 equals() 方法那么就无法保证元素的唯一。

2、LinkedHashSet集合

  LinkedHashSet集合元素有序并且元素唯一,因为它的底层数据结构是链表和哈希表,链表可以保证元素唯一,哈希表可以保证元素的唯一。

import java.util.LinkedHashSet;
public class MyTest {
    public static void main(String[] args) {
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
        linkedHashSet.add("爱");
        linkedHashSet.add("你");
        linkedHashSet.add("三");
        linkedHashSet.add("千");
        linkedHashSet.add("遍");
        linkedHashSet.add("三");
        linkedHashSet.add("千");
        linkedHashSet.add("遍");
        linkedHashSet.add("爱");
        for (String s : linkedHashSet) {
            System.out.println(s);
        }
    }
}
//运行结果为
爱你三千遍

  从运行结果可以看出,遍历的时候输出的顺序和存储的顺序相同,而后面重复的元素也没有重复存储。

3、TreeSet集合

  TreeSet集合的特点就是可以对集合进行排序,因为它的底层数据结果为二叉树。排序有两种方法,一种为自然排序,另一种为比较器排序。下面为大家简单来介绍一下这两种排序的方法。

a、自然排序

  当存储的元素为基本数据类型的时候,存储的时候就进行排序,当我们遍历的时候已经排好顺序了。举例说明

public class MyTest {
    public static void main(String[] args) {
        TreeSet<String> treeSet = new TreeSet<>();
        TreeSet<Integer> treeSet2 = new TreeSet<>();
        treeSet.add("a");
        treeSet.add("a");
        treeSet.add("b");
        treeSet.add("d");
        treeSet.add("c");
        treeSet2.add(24);
        treeSet2.add(19);
        treeSet2.add(18);
        treeSet2.add(24);
        for (String string : treeSet) {
            System.out.println(string);
        }
        System.out.println("------------");
        for (Integer integer : treeSet2) {
            System.out.println(integer);
        }
    }
}

运行结果如下图所示
Set集合
  由代码看出,元素在遍历的时候已经排好了顺序。


  当我们存储的为自定义类的元素时,我们需要这个自定义类实现 Comparable 接口重写里面的 comPareTo 方法,根据此方法的返回值的正负和0 来决定元素在二叉树的位置。下面让我们定义一个Student类,并对其进行测试。

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 String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student s) {
        //比较逻辑是按照年龄大小来排序
        int num = this.age - s.age;
        //当年龄相同不能说明他是同一个对象,还得比较姓名
        int num2 = num == 0 ? this.name.compareTo(s.name) : num;
        return num2;
    }
}
import java.util.TreeSet;

/**
 * @Author: Administrator
 * @CreateTime: 2019-05-11 10:31
 */
public class MyTest {
    public static void main(String[] args) {
        //按照学生的年龄大小来排序
        Student s1 = new Student("王五", 21);
        Student s11 = new Student("王五", 21);
        Student s123 = new Student("李四", 21);
        Student s2 = new Student("王五", 22);
        Student s3 = new Student("王五111", 25);
        Student s4 = new Student("王五123", 252);
        Student s5 = new Student("王五2222", 235);
        Student s6 = new Student("王五3", 25);
        Student s7 = new Student("欧阳王五", 2665);
        Student s8 = new Student("琦玉", 288);
        Student s9 = new Student("", 285);
        Student s10 = new Student("王五7", 255);
        TreeSet<Student> treeSet = new TreeSet<>();
        treeSet.add(s1);
        treeSet.add(s11);
        treeSet.add(s2);
        treeSet.add(s3);
        treeSet.add(s4);
        treeSet.add(s5);
        treeSet.add(s6);
        treeSet.add(s7);
        treeSet.add(s8);
        treeSet.add(s9);
        treeSet.add(s10);
        treeSet.add(s123);
        for (Student student : treeSet) {
            System.out.println(student);           
        }
    }
}

代码执行结果如下图
Set集合
  由代码执行的结果看,学生已经按照年龄排好了顺序,你想怎样排序就怎样重新compareTo方法中的逻辑。

b、比较器排序

  当使用比较器排序的时候,我们需要创建一个类来实现 Comparator 接口,然后重写里面的逻辑,然后再创建该类对象,传入到TreeSet集合中,但是不能每次我们使用比较器排序都要创建一个类,那么我们可以使用匿名对象直接传入,代码实现如下,学生类为上述学生类,测试类如下

import java.util.Comparator;
import java.util.TreeSet;
public class MyTest3 {
    public static void main(String[] args) {
        //传入一个比较器
        Comparator comparator = new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                //按照姓名长度来拍
                int num = s1.getName().length() - s2.getName().length();
                int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
                int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
                return num3;
            }
        };

        TreeSet<Student> treeSet = new TreeSet<>(comparator);
         treeSet.add(new Student("李", 21));
        treeSet.add(new Student("李十八", 212));
        treeSet.add(new Student("欧阳", 241));
        treeSet.add(new Student("王也", 2771));
        treeSet.add(new Student("王也也", 21733));
        treeSet.add(new Student("王也也", 21733));
        treeSet.add(new Student("王也也", 21337));
        treeSet.add(new Student("王也也", 217));
        treeSet.add(new Student("王也也", 217));
        for (Student student : treeSet) {
            System.out.println(student);
        }
    }
}

运行结果如下图

Set集合
  上面的代码是通过传入一个比较器来进行排序的,通过匿名对象传入了一个比较器然后重写compare()方法来确定元素在二叉树中的位置。

相关标签: HashSet Set