Java Comparator 接口

更新于 2025-12-25

Jakob Jenkov 2020-10-04

Java 的 Comparator 接口(java.util.Comparator)表示一个可以比较两个对象的组件,以便使用 Java 中的排序功能 对它们进行排序。例如,在对 Java List 进行排序时,你可以将一个 Comparator 传递给排序方法,该 Comparator 将在排序过程中用于比较列表中的对象。

Java 的 Comparator 接口与 Java Comparable 接口不同。Comparator 是被比较对象之外的一个独立组件,而 Comparable 是由被比较对象自身实现的接口。Comparable 所定义的排序顺序被称为对象的“自然排序顺序”,而 Comparator 的排序顺序则不是自然顺序。


Java Comparator 接口定义

Java 的 Comparator 接口位于 java.util 包中。其定义如下:

public interface Comparator<T> {
    public int compare(T o1, T o2);
}

注意,Comparator 接口只包含一个方法,即 compare() 方法。该方法接收两个待比较的对象,并返回一个 int 值,用以指示这两个对象的大小关系。返回值的语义如下:

  • 负数:第一个对象小于第二个对象。
  • 0:两个对象相等。
  • 正数:第一个对象大于第二个对象。

传递性比较(Transitive Comparison)

实现 Comparator 接口时,必须遵守以下传递性比较规则:

如果 A 大于 B,且 B 大于 C,那么 A 也必须大于 C。


实现 Java Comparator 接口

假设你有如下 Spaceship 类,希望对其对象进行比较:

public class Spaceship implements Comparable<Spaceship> {
    private String spaceshipClass = null;
    private String registrationNo = null;

    public Spaceship(String spaceshipClass, String registrationNo) {
        this.spaceshipClass = spaceshipClass;
        this.registrationNo = registrationNo;
    }

    public String getSpaceshipClass() {
        return spaceshipClass;
    }

    public String getRegistrationNo() {
        return registrationNo;
    }

    @Override
    public int compareTo(Spaceship other) {
        int spaceshipClassComparison = this.spaceshipClass.compareTo(other.spaceshipClass);
        if(spaceshipClassComparison != 0) {
            return spaceshipClassComparison;
        }
        return this.registrationNo.compareTo(other.registrationNo);
    }
}

注意:Spaceship 类已经实现了 Comparable 接口,首先按 spaceshipClass 比较,再按 registrationNo 比较。但如果你希望通过 Comparator 来比较对象,是否实现 Comparable 并不重要。

现在,假设你只想根据飞船的注册编号(registrationNo)进行排序,忽略 spaceshipClass。可以这样实现一个 Comparator

import java.util.Comparator;

public class SpaceshipComparator implements Comparator<Spaceship> {
    @Override
    public int compare(Spaceship o1, Spaceship o2) {
        return o1.getRegistrationNo().compareTo(o2.getRegistrationNo());
    }
}

几点说明:

  1. SpaceshipComparator 实现了 Comparator<Spaceship>,泛型 <Spaceship> 表明这个比较器只能用于 Spaceship 类型的对象。
  2. 使用泛型后,compare() 方法的参数类型就是 Spaceship,而不是 Object
  3. 几乎所有的 Comparator 实现都是针对特定类型的对象,因此使用泛型几乎总是有意义的。
  4. compare() 方法直接调用了 StringcompareTo() 方法来比较注册编号,这是一种完全合法的实现方式。

比较数字

如果你的 Comparator 需要比较的是数字,一种简便的方式是直接将两个数字相减并返回结果。

假设 Spaceship 类中的 registrationNoint 类型,那么比较逻辑可以写成:

import java.util.Comparator;

public class SpaceshipComparator implements Comparator<Spaceship> {
    @Override
    public int compare(Spaceship o1, Spaceship o2) {
        return o1.getRegistrationNo() - o2.getRegistrationNo();
    }
}

这种方式适用于整型数值的比较。但对于浮点数或可能溢出的情况需谨慎处理。