Comparator 和 Comparable

JavaJavaBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

介绍

在许多应用程序中,比较对象并对其进行排序是一个常见的需求。Java 提供了两个接口,ComparatorComparable,用于允许类根据某些标准定义其自身的自然顺序。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL java(("`Java`")) -.-> java/DataStructuresGroup(["`Data Structures`"]) java(("`Java`")) -.-> java/ObjectOrientedandAdvancedConceptsGroup(["`Object-Oriented and Advanced Concepts`"]) java/DataStructuresGroup -.-> java/sorting("`Sorting`") java/DataStructuresGroup -.-> java/collections_methods("`Collections Methods`") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/classes_objects("`Classes/Objects`") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/oop("`OOP`") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/interface("`Interface`") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/arraylist("`ArrayList`") subgraph Lab Skills java/sorting -.-> lab-117394{{"`Comparator 和 Comparable`"}} java/collections_methods -.-> lab-117394{{"`Comparator 和 Comparable`"}} java/classes_objects -.-> lab-117394{{"`Comparator 和 Comparable`"}} java/oop -.-> lab-117394{{"`Comparator 和 Comparable`"}} java/interface -.-> lab-117394{{"`Comparator 和 Comparable`"}} java/arraylist -.-> lab-117394{{"`Comparator 和 Comparable`"}} end

实现 Comparable 接口

要实现 Comparable 接口,类需要定义其自然排序规则。这是通过重写 compareTo() 方法来实现的。compareTo() 方法返回一个负整数、零或正整数,分别表示调用对象小于、等于或大于方法的参数。

以下代码块展示了一个实现 Comparable 接口的 Student 类的示例:

class Student implements Comparable<Student> {
    private String name;
    private int gpa;
    private int regNo;

    public Student(String name, int gpa, int regNo) {
        this.name = name;
        this.gpa = gpa;
        this.regNo = regNo;
    }

    // 重写 compareTo() 方法
    @Override
    public int compareTo(Student other) {
        return this.gpa - other.gpa;
    }

    // Getters 和 setters
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getGpa() {
        return gpa;
    }

    public void setGpa(int gpa) {
        this.gpa = gpa;
    }

    public int getRegNo() {
        return regNo;
    }

    public void setRegNo(int regNo) {
        this.regNo = regNo;
    }
}

compareTo() 方法中,我们根据学生的 gpa 定义了排序规则。

使用 Collections.sort() 方法对对象进行排序

在实现了 compareTo() 方法后,我们可以使用 Collections.sort() 方法对 Student 对象列表进行排序。以下代码块展示了这一过程:

ArrayList<Student> studentList = new ArrayList<>();
studentList.add(new Student("John", 3, 101));
studentList.add(new Student("Mary", 4, 102));
studentList.add(new Student("Alice", 3, 103));

Collections.sort(studentList);

for (Student s : studentList) {
    System.out.println(s.getName() + ", GPA: " + s.getGpa());
}

Collections.sort() 方法会根据 compareTo() 方法定义的规则,按照 gpa 的升序对列表中的 Student 对象进行排序。

实现 Comparator 接口

在某些情况下,你可能希望根据不同的标准对对象进行排序。在这种情况下,我们可以使用 Comparator 接口。

Comparator 接口提供了一个 compare() 方法,该方法接受两个参数,并返回一个负整数、零或正整数,分别表示第一个参数小于、等于或大于第二个参数。

以下是一个 Student 类的示例,其中实现了 Comparator 接口以按名称排序:

class StudentNameComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        return s1.getName().compareTo(s2.getName());
    }
}

使用 Comparator 对对象进行排序

要使用 Comparator 对对象进行排序,可以使用 Collections 类的 sort() 方法。sort() 方法有一个重载版本,接受一个类型为 Comparator 的额外参数。

以下是一个使用 StudentNameComparator 类按名称对 Student 对象进行排序的示例:

ArrayList<Student> studentList = new ArrayList<>();
studentList.add(new Student("John", 3, 101));
studentList.add(new Student("Mary", 4, 102));
studentList.add(new Student("Alice", 3, 103));

StudentNameComparator nameComparator = new StudentNameComparator();
Collections.sort(studentList, nameComparator);

for (Student s : studentList) {
    System.out.println(s.getName() + ", GPA: " + s.getGpa());
}

Collections.sort() 方法使用 nameComparator 对象按字母顺序对 Student 对象进行排序。

按多个条件对对象进行排序

在某些情况下,你可能希望根据多个条件对对象进行排序。例如,你可能希望先按 gpaStudent 对象进行排序,然后再按名称排序。

你可以通过使用 Comparator 接口的 thenComparing() 方法将多个比较器链接起来实现这一点。

以下是一个 Student 类的示例,其中包含一个按 gpa 和名称排序的比较器:

class StudentGpaNameComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        int gpaCompare = s1.getGpa() - s2.getGpa();
        if (gpaCompare != 0) {
            return gpaCompare;
        }
        return s1.getName().compareTo(s2.getName());
    }
}

StudentGpaNameComparator 类根据 Student 对象的 gpa 进行比较。如果 gpa 相同,则通过比较 Student 对象的名称来打破平局。

使用 thenComparing() 按多个条件对对象进行排序

要按多个条件对对象进行排序,可以使用 Comparator 接口的 thenComparing() 方法。thenComparing() 方法接受一个 Comparator 对象作为参数,并返回一个新的 Comparator 对象,该对象将之前的 Comparator 与新的 Comparator 链接起来。

以下是一个使用 StudentGpaNameComparator 类对 Student 对象进行排序的示例:

ArrayList<Student> studentList = new ArrayList<>();
studentList.add(new Student("John", 3, 101));
studentList.add(new Student("Mary", 4, 102));
studentList.add(new Student("Alice", 3, 103));
studentList.add(new Student("Joe", 4, 104));

StudentGpaNameComparator gpaNameComparator = new StudentGpaNameComparator();
Collections.sort(studentList, gpaNameComparator);

for (Student s : studentList) {
    System.out.println(s.getName() + ", GPA: " + s.getGpa());
}

Collections.sort() 方法使用 gpaNameComparator 对象根据 Student 对象的 gpa 进行排序,然后再按名称排序。

按降序排序

默认情况下,Collections.sort() 方法按升序对对象进行排序。要按降序对对象进行排序,可以使用 Comparator 接口的 reverseOrder() 方法。该方法返回一个 Comparator 对象,该对象按自然顺序的相反顺序对对象进行排序。

以下是一个按 GPA 降序对 Student 对象进行排序的示例:

ArrayList<Student> studentList = new ArrayList<>();
studentList.add(new Student("John", 3, 101));
studentList.add(new Student("Mary", 4, 102));
studentList.add(new Student("Alice", 3, 103));
studentList.add(new Student("Joe", 4, 104));

Comparator<Student> reverseGpaComparator = Collections.reverseOrder();
Collections.sort(studentList, new StudentGpaComparator().thenComparing(new StudentNameComparator()).reversed());

for (Student s : studentList) {
    System.out.println(s.getName() + ", GPA: " + s.getGpa());
}

reverseGpaComparator 对象用于按 gpa 降序对 Student 对象进行排序。thenComparing() 方法用于按名称作为平局决胜条件对 Student 对象进行排序。最后,reversed() 方法用于反转整个比较的顺序。

综合应用

现在你已经了解了如何使用 ComparableComparator 对对象进行排序,让我们将所有内容整合到一个 Java 类中:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

class Student implements Comparable<Student> {
    private String name;
    private int gpa;
    private int regNo;

    public Student(String name, int gpa, int regNo) {
        this.name = name;
        this.gpa = gpa;
        this.regNo = regNo;
    }

    // 重写 compareTo() 以实现自然排序
    @Override
    public int compareTo(Student other) {
        return this.gpa - other.gpa;
    }

    // Getter 和 Setter 方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getGpa() {
        return gpa;
    }

    public void setGpa(int gpa) {
        this.gpa = gpa;
    }

    public int getRegNo() {
        return regNo;
    }

    public void setRegNo(int regNo) {
        this.regNo = regNo;
    }
}

class StudentNameComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        return s1.getName().compareTo(s2.getName());
    }
}

class StudentGpaComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        return s1.getGpa() - s2.getGpa();
    }
}

class StudentGpaNameComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        int gpaCompare = s1.getGpa() - s2.getGpa();
        if (gpaCompare != 0) {
            return gpaCompare;
        }
        return s1.getName().compareTo(s2.getName());
    }
}

public class ComparatorComparable {
    public static void main(String[] args) {
        ArrayList<Student> studentList = new ArrayList<>();
        studentList.add(new Student("John", 3, 101));
        studentList.add(new Student("Mary", 4, 102));
        studentList.add(new Student("Alice", 3, 103));
        studentList.add(new Student("Joe", 4, 104));

        // 使用 compareTo() 按 GPA 排序
        Collections.sort(studentList);

        System.out.println("按 GPA 排序:");
        for (Student s : studentList) {
            System.out.println(s.getName() + ", GPA: " + s.getGpa());
        }

        // 使用 Comparator 按名称排序
        StudentNameComparator nameComparator = new StudentNameComparator();
        Collections.sort(studentList, nameComparator);

        System.out.println("\n按名称排序:");
        for (Student s : studentList) {
            System.out.println(s.getName() + ", GPA: " + s.getGpa());
        }

        // 使用 Comparator 链按 GPA 和名称排序
        StudentGpaNameComparator gpaNameComparator = new StudentGpaNameComparator();
        Collections.sort(studentList, gpaNameComparator);

        System.out.println("\n按 GPA 和名称排序:");
        for (Student s : studentList) {
            System.out.println(s.getName() + ", GPA: " + s.getGpa());
        }

        // 使用 Comparator 链按 GPA 降序和名称升序排序
        Comparator<Student> reverseGpaComparator = Collections.reverseOrder();
        Collections.sort(studentList, new StudentGpaComparator().thenComparing(new StudentNameComparator()).reversed());

        System.out.println("\n按 GPA 降序和名称升序排序:");
        for (Student s : studentList) {
            System.out.println(s.getName() + ", GPA: " + s.getGpa());
        }
    }
}

运行代码

要运行代码示例,请将文件保存为 ComparatorComparable.java,然后在终端中运行以下命令:

cd ~/project
javac ComparatorComparable.java
java ComparatorComparable

你应该会看到根据不同排序条件排序后的 Student 对象的输出。

总结

在本实验中,你学习了如何在 Java 中使用 ComparableComparator 接口,根据不同的条件对对象进行排序。

具体来说,你学习了如何实现 Comparable 接口,以基于类的条件定义自然排序。你还学习了如何使用 Comparator 接口,根据不同的条件定义排序,并链式组合多个比较器。

最后,你学习了如何使用 Collections.sort() 方法对对象进行排序,以及如何使用 reverseOrder() 方法对对象进行降序排序。

您可能感兴趣的其他 Java 教程