Comparator 与 Comparable 的比较

`Comparable`是内部比较器,定义类的自然排序,需实现`compareTo`方法;`Comparator`是外部比较器,提供灵活的自定义排序,通过`compare`方法实现。前者侵入性强但单一,后者无需修改类且支持多规则排序。

作者头像
LumiBee
7 天前 · 26 0
分享

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 表达式。
  • 作用:
    1. 为一个没有实现 Comparable 接口的类提供排序逻辑。
    2. 为一个已经实现 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)
阅读量: 26

评论区

登录后发表评论

正在加载评论...
相关阅读

Comparator 与 Lambda 表达式结合使用

# Comparator 与 Lambda 结合 ## 1. 天作之合 原因:`Comparator` 是一个**函数式接口** (Functional Interface,如果一个接口只要...

2
0

Java单列集合学习

# Collection Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的 * List接口的实现类 * ArrayList:动态数组实现,允许重复元素 ...

100
1

Java双列集合学习

# Map ## 特点: 1. 双列集合一次要存储一对数据,分别为键和值 2. 键不能重复,值可以重复 3. 键和值是一一对应的,每一个键只能找到自己对应的值 4. 键+值的整体,称之为“键...

132
0