Comparator 与 Comparable 的比较
它们都是用来给对象排序的,但实现方式和使用场景有所不同:
Comparable
:内部比较器,定义了类的自然排序。一个类一旦实现了它,就意味着这个类的对象“天生”就具备了可比性。Comparator
:外部比较器,定义了自定义或临时排序。当一个类的自然排序不符合你的需求,或者类本身没有实现Comparable
接口时,你可以创建一个外部的比较器来对它进行排序。
1. Comparable 接口
Comparable
接口是“天生如此”或“内建的”排序规则。
- 包 : `java.lang.Comparable
- 核心方法:
int compareTo(T o)
- 实现方式: 需要排序的类自己实现
Comparable
接口,并重写compareTo
方法。 - 作用: 定义对象的自然排序。例如,
String
类按字典序排序,Integer
类按数字大小排序,这些都是它们的自然排序。
compareTo(T o)
方法的返回值:
- 返回正数: 表示当前对象 (
this
) 大于传入的对象 (o
)。 - 返回负数: 表示当前对象 (
this
) 小于传入的对象 (o
)。 - 返回零: 表示当前对象 (
this
) 等于传入的对象 (o
)。
假设我们有一个 Student
类,我们希望它默认按年龄从小到大排序。
public class Student implements Comparable<Student> {
private String name;
private int age;
// 构造函数、getter 和 setter 省略...
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" + "name='" + name + '\'' + ", age=" + age + '}';
}
// 实现 compareTo 方法,定义自然排序规则
@Override
public int compareTo(Student other) {
// 按年龄升序排序
return this.age - other.age;
}
}
// 使用
List<Student> students = new ArrayList<>();
students.add(new Student("Alice", 20));
students.add(new Student("Bob", 18));
students.add(new Student("Charlie", 22));
Collections.sort(students); // 无需指定比较器,直接使用 Student 类定义的自然排序
// 输出结果将按年龄排序:[Student{name='Bob', age=18}, Student{name='Alice', age=20}, Student{name='Charlie', age=22}]
2. Comparator 接口
Comparator
接口是“后天赋予”或“外置的”排序规则。
- 包:
java.util.Comparator
- 核心方法:
int compare(T o1, T o2)
- 实现方式: 创建一个单独的类来实现
Comparator
接口,或者使用匿名内部类 Lambda 表达式。 - 作用:
- 为一个没有实现
Comparable
接口的类提供排序逻辑。 - 为一个已经实现
Comparable
接口的类提供多种不同的排序方式。
- 为一个没有实现
compare(T o1, T o2)
方法的返回值:
- 返回正数: 表示
o1
大于o2
。 - 返回负数: 表示
o1
小于o2
。 - 返回零: 表示
o1
等于o2
。
继续使用上面的 Student
类。它的自然排序是按年龄,但现在我们想按名字的字母顺序来排序。这时就需要 Comparator
。
方法一:创建一个单独的比较器类
public class SortByNameComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
// 按姓名进行字符串比较
return s1.getName().compareTo(s2.getName());
}
}
List<Student> students = ...; // 和上面一样的列表
Collections.sort(students, new SortByNameComparator()); // 传入一个比较器实例
// 输出结果将按姓名排序:[Student{name='Alice', age=20}, Student{name='Bob', age=18}, Student{name='Charlie', age=22}]
方法二:使用 Lambda 表达式
List<Student> students = ...; // 和上面一样的列表
// 直接在 sort 方法中用 Lambda 表达式定义排序规则
students.sort((s1, s2) -> s1.getName().compareTo(s2.getName()));
// 或者使用 Comparator 的静态辅助方法
students.sort(Comparator.comparing(Student::getName));
3. 总结与对比
特性 | Comparable |
Comparator |
---|---|---|
定义 | 内部比较器 | 外部比较器 |
目的 | 定义类的自然排序 | 定义类的自定义排序或多种排序 |
包位置 | java.lang |
java.util |
核心方法 | int compareTo(T o) |
int compare(T o1, T o2) |
实现位置 | 在需要排序的类内部实现接口 | 在一个单独的类或Lambda表达式中实现 |
侵入性 | 高,需要修改类的源代码 | 低,无需修改类的源代码 |
灵活性 | 低,一种类只有一种自然排序 | 高,可以为同一个类定义任意多种排序规则 |
典型使用 | Collections.sort(list) Arrays.sort(array) |
Collections.sort(list, comparator) Arrays.sort(array, comparator) list.sort(comparator) |
评论区
请登录后发表评论