Java-集合(三) Set接口

Set
–HashSet 使用散列函数实现,极大的提高了访问速度。存入HashSet的对象必须定义hashCode()
–LinkedHashSet 使用了链表来保持插入顺序,不过为了提高查询效率,也使用了散列。
–TreeSet 使用红黑树来实现, 时刻维持有序,平衡.

Set方法比List方法少一点
示例代码1

import java.util.*;

public class TestSet {
    public static void main(String[] args) {
        //以下三种方式都可以得到一个set。输出也是一样的,只不过底层实现不同
        Set<String> set = new HashSet<>();
//        Set<String> set = new LinkedHashSet<>();
//        Set<String> set = new TreeSet<>();

        set.add("java");
        set.add("Oracle");
        set.add("HTML");
        set.add("java");

        System.out.println(set.size());
        System.out.println(set);

//        foreach 循环遍历
//        for (String elem:set) {
//            System.out.println(elem);
//
//        }

        //因为set没有定义set方法和get方法,所以不能直接用for循环遍历

        //Iterator迭代器遍历
        Iterator<String> it = set.iterator();
        while (it.hasNext()){
            String elem = it.next();
            System.out.println(elem);
        }
    }
}

示例代码2

import java.util.HashSet;
import java.util.Set;

public class TestSet2 {
    public static void main(String[] args) {
        Set<Student> set = new HashSet<Student>();

        Student stu1 = new Student(1, "张三", 15, 87);
        Student stu2 = new Student(2, "李四", 16, 88);
        Student stu3 = new Student(3, "王五", 14, 65);
        Student stu4 = new Student(4, "赵六", 19, 83);
        Student stu5 = new Student(1, "张三", 15, 87);

        set.add(stu1);
        set.add(stu2);
        set.add(stu3);
        set.add(stu4);
        set.add(stu5);

        System.out.println(set.size());
        for (Student s: set) {
            System.out.println(s);
        }

    }
}

其中 Student 类:
有四个成员变量,实现了set和get方法,并实现了构造方法(有参和无参),还实现了toString方法.
示例代码3

public class Student {

    private int sno;
    private String name;
    private int age;
    private double score;

    public Student(int sno, String name, int age, double score) {
        this.sno = sno;
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public Student() {
    }

    public int getSno() {
        return sno;
    }

    public void setSno(int sno) {
        this.sno = sno;
    }

    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 double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "sno=" + sno +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
}

上面代码执行的结果是

5
Student{sno=1, name='张三', age=15, score=87.0}
Student{sno=1, name='张三', age=15, score=87.0}
Student{sno=4, name='赵六', age=19, score=83.0}
Student{sno=3, name='王五', age=14, score=65.0}
Student{sno=2, name='李四', age=16, score=88.0}

可以发现此时HashSet存储Student类的时候并没有实现不重复的功能,第一条跟第二条内容完全一样,但是却都在HashSet里面.这与实际要求情况不符.

解决方法:
重写 Student 类的equals() 和 hashCode() 方法
这个也可以用IDE自动生成.也可以参考另一篇博客详细讲解如何重写.
示例代码4

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return sno == student.sno &&
                age == student.age &&
                Double.compare(student.score, score) == 0 &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(sno, name, age, score);
    }

此时再次执行TestSet2,发现成功了:

4
Student{sno=4, name='赵六', age=19, score=83.0}
Student{sno=3, name='王五', age=14, score=65.0}
Student{sno=2, name='李四', age=16, score=88.0}
Student{sno=1, name='张三', age=15, score=87.0}

这里自动生成的是按照学号从大到小排序.

重要

·将元素放入到hashSet和LinkedHashSet等底层结构是哈希表的集合中时,需要重写 equals 和 hashCode方法.
·将元素放入TreeSet等底层结构是二叉排序树的集合中时,需要实现Comparable接口或Comparator接口

TreeSet 底层是 TreeMap
Comparator 外部比较器(优先)
comparable 内部比较器 该类对外提供一个默认比较的实现

最终的Student类代码如下:
示例代码5

import java.util.Objects;

public class Student implements Comparable<Student>{

    private int sno;
    private String name;
    private int age;
    private double score;

    public Student(int sno, String name, int age, double score) {
        this.sno = sno;
        this.name = name;
        this.age = age;
        this.score = score;
    }

    public Student() {
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return sno == student.sno &&
                age == student.age &&
                Double.compare(student.score, score) == 0 &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(sno, name, age, score);
    }

    public int getSno() {
        return sno;
    }

    public void setSno(int sno) {
        this.sno = sno;
    }

    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 double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "sno=" + sno +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }

    @Override
    public int compareTo(Student other) {
        return this.sno - other.sno;
    }
}

另两个执行代码就不展示了,与示例代码二类似.

猜你喜欢

转载自blog.csdn.net/Yolandera/article/details/82594071