📌  相关文章
📜  如何在Java中使用用户定义的对象对 TreeSet 进行排序?(1)

📅  最后修改于: 2023-12-03 15:24:32.119000             🧑  作者: Mango

如何在Java中使用用户定义的对象对 TreeSet 进行排序?

在 Java 中,TreeSet 是一种基于红黑树实现的有序集合,它可以对元素进行排序。然而,对于用户自定义的对象,需要实现 Comparable 接口,重写 compareTo 方法来指定排序规则。本篇文章将介绍如何在 Java 中使用用户定义的对象对 TreeSet 进行排序。

实现 Comparable 接口

首先,我们需要定义一个用户自定义的对象,比如一个学生类。然后,我们要让这个学生类实现 java.lang.Comparable 接口,重写 compareTo 方法。

public class Student implements Comparable<Student> {
    private String name;
    private int age;
    private int score;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public int getScore() {
        return score;
    }

    @Override
    public int compareTo(Student otherStudent) {
        int result = this.name.compareTo(otherStudent.name);
        if (result == 0) {
            result = Integer.compare(this.age, otherStudent.age);
            if (result == 0) {
                result = Integer.compare(this.score, otherStudent.score);
            }
        }
        return result;
    }
}

在 compareTo 方法中,我们首先按照学生姓名进行比较,如果姓名相同,则按照年龄比较,如果年龄也相同,则按照成绩比较。这样,我们就定义了一个基于姓名、年龄和成绩来比较两个学生对象的方法。

注意:compareTo 方法必须具有以下特性:

  • 自反性:x.compareTo(y) 和 y.compareTo(x) 的结果应该相反。
  • 对称性:如果 x.compareTo(y) 的结果是负数,那么 y.compareTo(x) 的结果应该是正数,反之亦然。
  • 传递性:如果 x.compareTo(y) 是负数并且 y.compareTo(z) 是负数,那么 x.compareTo(z) 也应该是负数。
  • 一致性:如果 x.compareTo(y) 的结果为 0,则无论多少次调用也应该返回 0。
  • null 敏感性:x.compareTo(null) 应该抛出 NullPointerException 异常。
使用 TreeSet 排序

现在我们已经定义了一个实现了 Comparable 接口的学生类,可以使用 TreeSet 对学生对象进行排序了。下面是一个使用 TreeSet 实现排序的示例代码:

import java.util.*;

public class TreeSetExample {
    public static void main(String[] args) {
        Student[] students = new Student[] {
            new Student("Tom", 18, 90),
            new Student("Jerry", 20, 85),
            new Student("Mike", 19, 88),
            new Student("Tom", 20, 95),
            new Student("Rick", 18, 85)
        };

        TreeSet<Student> treeSet = new TreeSet<>();
        Collections.addAll(treeSet, students);

        for (Student student : treeSet) {
            System.out.printf("name: %s, age: %d, score: %d\n",
                student.getName(), student.getAge(), student.getScore());
        }
    }
}

运行结果如下:

name: Jerry, age: 20, score: 85
name: Mike, age: 19, score: 88
name: Rick, age: 18, score: 85
name: Tom, age: 18, score: 90
name: Tom, age: 20, score: 95

可以看到,TreeSet 对学生对象按照我们定义的 compareTo 方法进行了排序,而且没有重复元素。

实现 Comparator 接口

除了让学生类实现 Comparable 接口,我们也可以定义一个实现了 java.util.Comparator 接口的比较类来指定排序规则。Comparator 接口和 Comparable 接口的区别在于,Comparable 接口是让对象自己实现比较逻辑,而 Comparator 接口则是让第三方实现比较逻辑。如果我们要使用 Comparator 接口,需要在创建 TreeSet 对象时传入比较器:

TreeSet<Student> treeSet = new TreeSet<>(new StudentComparator());

如下是一个使用 Comparator 接口实现排序的示例代码:

import java.util.*;

public class ComparatorExample {
    public static void main(String[] args) {
        Student[] students = new Student[] {
            new Student("Tom", 18, 90),
            new Student("Jerry", 20, 85),
            new Student("Mike", 19, 88),
            new Student("Tom", 20, 95),
            new Student("Rick", 18, 85)
        };

        TreeSet<Student> treeSet = new TreeSet<>(new StudentComparator());
        Collections.addAll(treeSet, students);

        for (Student student : treeSet) {
            System.out.printf("name: %s, age: %d, score: %d\n",
                student.getName(), student.getAge(), student.getScore());
        }
    }
}

class StudentComparator implements Comparator<Student> {
    @Override
    public int compare(Student student1, Student student2) {
        int result = Integer.compare(student1.getScore(), student2.getScore());
        if (result == 0) {
            result = Integer.compare(student1.getAge(), student2.getAge());
            if (result == 0) {
                result = student1.getName().compareTo(student2.getName());
            }
        }
        return result;
    }
}

运行结果如下:

name: Jerry, age: 20, score: 85
name: Rick, age: 18, score: 85
name: Mike, age: 19, score: 88
name: Tom, age: 18, score: 90
name: Tom, age: 20, score: 95

可以看到,TreeSet 对学生对象按照我们定义的 StudentComparator 进行了排序,而且没有重复元素。

总结

Java 中的 TreeSet 可以对元素进行排序,但对于用户自定义的对象,需要实现 Comparable 接口,重写 compareTo 方法来指定排序规则。如果不想修改原有类的代码,也可以定义一个实现了 Comparator 接口的比较类来指定排序规则。使用 TreeSet 进行排序时需要注意 Comparable 和 Comparator 接口的特性,以及 null 值的处理。