Set集合:无序(存储顺序和取出顺序不一致),唯一。

Set子类:HashSet、LinkedHashSet、TreeSet。

一、HashSet

HashSet:不保证Set的迭代顺序,特别是它不保证该顺序永恒不变。

底层数据结构是哈希表(元素的链表的数组)。

哈希表依赖于哈希值存储。

添加功能底层依赖两个方法:

(1). int hashCode()

(2).boolean equals(Object obj)

首先比较哈希值,如果相同,则比较地址值是否相同或者equals。

代码示例1:

//测试Set集合无序,唯一
Set<String> set = new HashSet<String>();
set.add("hello world");
set.add("java");
set.add("您好");
set.add("hello world");
set.add("java");
for (String s:set) {
    System.out.println(s);
}

打印结果:

java
您好
hello world

示例代码2:

public class GenericTest {
    public static void main(String[] args) {
        
        HashSet<Student> set = new HashSet<Student>();
        Student student1 = new Student("张三",18);
        Student student2 = new Student("李四",19);
        Student student3 = new Student("王五",20);
        Student student4 = new Student("张三",21);
        Student student5 = new Student("李四",19);

        set.add(student1);
        set.add(student2);
        set.add(student3);
        set.add(student4);
        set.add(student5);

        for (Student student : set){
            System.out.println("姓名:"+student.getName()+"    年龄:"+student.getAge());
        }

    }
}
class Student{

    private String name;
    private int age;

    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;
    }
}

打印结果:

姓名:李四    年龄:19
姓名:张三    年龄:18
姓名:王五    年龄:20
姓名:李四    年龄:19
姓名:张三    年龄:21

结果出现重复数据:原因是因为HashSet底层依赖的是hashCode()方法和equals方法。

而这两个方法在Student中没有重写,所以默认使用的是Object类。

实例化Student对象的哈希值不同,所以出现重复数据。

重写hashCode()方法和equals方法代码示例:

public class GenericTest {
    public static void main(String[] args) {
        //测试Set集合无序,唯一
        HashSet<Student> set = new HashSet<Student>();
        Student student1 = new Student("张三",18);
        Student student2 = new Student("李四",19);
        Student student3 = new Student("王五",20);
        Student student4 = new Student("张三",21);
        Student student5 = new Student("李四",19);

        set.add(student1);
        set.add(student2);
        set.add(student3);
        set.add(student4);
        set.add(student5);

        for (Student student : set){
            System.out.println("姓名:"+student.getName()+"    年龄:"+student.getAge());
        }

    }
}
class Student{

    private String name;
    private int age;

    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 int hashCode() {
        return 0;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj){
            return true;
        }
        if (!(obj instanceof Student)){
            return false;
        }

        Student s = (Student)obj;
        return this.name.equals(s.name) && this.age == s.age;
    }
}

打印结果为:

姓名:张三    年龄:18
姓名:李四    年龄:19
姓名:王五    年龄:20
姓名:张三    年龄:21

二、LinkedHashSet

LinkedHashSet 底层数据结构由哈希表和链表组成。

哈希表保证元素的唯一性。

链表保证元素有序(存储和取出一致)。

代码示例:

LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();
linkedHashSet.add("hello world");
linkedHashSet.add("java");
linkedHashSet.add("您好");
linkedHashSet.add("hello world");
linkedHashSet.add("java");
linkedHashSet.add("您好");
for (String s : linkedHashSet){
    System.out.println(s);
}

打印结果:

hello world
java
您好

三、TreeSet

1.自然排序:使用元素的自然顺序对元素进行排序。自然排序需要类实现Comparable接口,重写Compareto方法 。

2.比较器排序: 实现Comparator接口,并重写compare(T o1, T o2)方法:

TreeSet底层数据结构是红黑树(红黑树是一种自平横的二叉树)。

代码示例1:自然排序

TreeSet<Integer> treeSet = new TreeSet<Integer>();
treeSet.add(20);
treeSet.add(19);
treeSet.add(18);
treeSet.add(24);
treeSet.add(9);
treeSet.add(27);
treeSet.add(26);
treeSet.add(20);
treeSet.add(7);
treeSet.add(50);
treeSet.add(1);
for (Integer integer : treeSet){
    System.out.println(integer);
}

打印结果:

1
7
9
18
19
20
24
26
27
50

按自然排序并且去掉重复数据:自然排序和唯一性。

代码示例2:自然排序

public class GenericTest {
    public static void main(String[] args) {
        //TreeSet存储自定义对象并保证排序和唯一性,自然排序。
        TreeSet<Student> treeSet = new TreeSet<Student>();
        treeSet.add(new Student("zhangsan",21));
        treeSet.add(new Student("lisi",25));
        treeSet.add(new Student("wangwu",24));
        treeSet.add(new Student("zhangsan",27));
        treeSet.add(new Student("yangtong",31));
        treeSet.add(new Student("lisi",25));
        treeSet.add(new Student("jiabaoyu",20));
        treeSet.add(new Student("lindaiyu",19));

        for (Student student : treeSet){
            System.out.println("姓名:"+student.getName()+"     年龄:"+student.getAge());
        }
    }
}
class Student implements Comparable<Student>{

    private String name;
    private int age;

    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 int compareTo(Student o) {
        //按年龄进行排序
        int num = this.age - o.age;

        int num2 = num == 0 ? this.name.compareTo(o.name) : num;

        return num2;
    }
}

打印结果:

姓名:lindaiyu     年龄:19
姓名:jiabaoyu     年龄:20
姓名:zhangsan     年龄:21
姓名:wangwu     年龄:24
姓名:lisi     年龄:25
姓名:zhangsan     年龄:27
姓名:yangtong     年龄:31

代码示例3:定义比较器排序

public class GenericTest {
    public static void main(String[] args) {
        //
        TreeSet<Student> treeSet = new TreeSet<Student>(new MyComparetor());

        treeSet.add(new Student("zhangsan",21));
        treeSet.add(new Student("lisi",25));
        treeSet.add(new Student("wangwu",24));
        treeSet.add(new Student("zhangsan",27));
        treeSet.add(new Student("yangtong",31));
        treeSet.add(new Student("lisi",25));
        treeSet.add(new Student("jiabaoyu",20));
        treeSet.add(new Student("lindaiyu",19));

        for (Student student : treeSet){
            System.out.println("姓名:"+student.getName()+"     年龄:"+student.getAge());
        }
    }
}
class Student{

    private String name;
    private int age;

    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 int compareTo(Student o) {
        //按年龄进行排序
        int num = this.age - o.age;

        int num2 = num == 0 ? this.name.compareTo(o.name) : num;

        return num2;
    }*/
}
class MyComparetor implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        //按年龄进行排序
        int num = o1.getAge() - o2.getAge();

        int num2 = num == 0 ? o1.getName().compareTo(o2.getName()) : num;

        return num2;
    }
}

打印结果:

姓名:lindaiyu     年龄:19
姓名:jiabaoyu     年龄:20
姓名:zhangsan     年龄:21
姓名:wangwu     年龄:24
姓名:lisi     年龄:25
姓名:zhangsan     年龄:27
姓名:yangtong     年龄:31