Comparator 接口
本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 45 课,共 87 课。
虽然 Comparable 定义了类的自然顺序,但有时你需要用不同的方式对对象进行排序。Comparator 接口可以让你创建独立的比较逻辑,而无需修改原来的类。
Comparator 是一个外部对象,用于比较两个相同类型的对象。当你想要多种排序方式,或者无法修改类本身时,这会很有用:
import java.util.Comparator;
class NameComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
}
class AgeComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
}然后,你可以将比较器传递给排序方法:
List<Person> people = new ArrayList<>();
people.add(new Person("Charlie", 30));
people.add(new Person("Alice", 25));
Collections.sort(people, new NameComparator()); // 按姓名排序
Collections.sort(people, new AgeComparator()); // 按年龄排序为了让代码更简洁,你可以使用 lambda 表达式,因为 Comparator 是一个函数式接口:
Collections.sort(people, (p1, p2) -> p1.getName().compareTo(p2.getName()));关键区别:Comparable由被比较的类实现,用于定义一种自然顺序;而Comparator是一个独立的类,可以定义无限种自定义顺序。
挑战
简单让我们构建一个员工排序系统,展示 Comparator 接口的强大之处。你将创建多个比较器,以不同方式按薪资和姓名对员工进行排序,而无需修改 Employee 类本身。
你将把代码分成 4 个文件:
Employee.java:创建一个表示员工的类,其中包含 3 个私有字段:name(String)、department(String)和salary(double)。添加一个用于初始化所有字段的构造函数,以及每个字段对应的 getter 方法。重写toString(),使其返回:[name] ([department]) - $[salary]SalaryComparator.java:创建一个比较器,按薪资降序排列员工(薪资最高的排在最前)。实现Comparator<Employee>接口及其compare()方法。使用Double.compare()安全地比较薪资值。NameComparator.java:再创建一个比较器,按姓名字母顺序升序排列员工(从 A 到 Z)。实现Comparator<Employee>,并使用 String 的compareTo()方法进行比较。Main.java:创建员工列表,并使用你的比较器对员工进行排序,将所有内容整合起来。你将收到 3 名员工的输入,每名员工占一行,格式为:name,department,salary创建一个员工
ArrayList,然后演示这两种排序方式:- 首先,使用你的
SalaryComparator按薪资排序,并打印每名员工 - 打印一个空行
- 然后,使用你的
NameComparator按姓名排序,并打印每名员工
- 首先,使用你的
你将收到 3 行输入,每行包含一名员工的数据,格式为:name,department,salary
例如,输入行可能如下所示:Alice,Engineering,75000.0
记得在比较器文件中导入 java.util.Comparator,并在 Main 文件中导入 java.util.ArrayList、java.util.Collections 和 java.util.Scanner。注意,比较器让你可以在外部定义多种排序策略:Employee 类本身不需要了解如何对它进行排序!
亲手试试
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 从输入中读取 3 名员工的信息
// 每行的格式:name,department,salary
String line1 = scanner.nextLine();
String line2 = scanner.nextLine();
String line3 = scanner.nextLine();
// TODO: 解析每一行并创建 Employee 对象
// 提示:使用 split(",") 分隔各个值
// TODO: 创建一个存放员工的 ArrayList,并将这 3 名员工全部加入其中
// TODO: 使用 SalaryComparator 按薪资排序,并打印每名员工的信息
// 提示:使用 Collections.sort(list, comparator)
// TODO: 打印一个空行
// TODO: 使用 NameComparator 按姓名排序,并打印每名员工的信息
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
7特殊方法与 Object 类
toString() 方法equals() 和 hashCode()clone() 方法compareTo() 和 ComparableComparator 接口回顾:自定义排序自己练习: Java 在线编译器