playground

Comparable和Comparator

Comparable

一个类如果实现了Comparable接口就表示该类是可比较的,可以用Collections.sort()Arrays.sort()对该类的集合或数组进行排序:

public interface Comparable<T> {
    public int compareTo(T o);
}

该接口只有一个方法,如果this.compareTo(o)返回负值就表示thiso小,返回零则表示两个对象相等,否则表示thiso大。

下面是一个例子:

public class Film implements Comparable<Film> {

    private int score;

    public Film(int score) {
        this.score = score;
    }

    @Override
    public int compareTo(Film o) {
        return this.score - o.score;
    }
}

public static void main(String[] args) {
    List<Film> films = new ArrayList<>();
    films.add(new Film(65));
    films.add(new Film(60));
    films.add(new Film(80));

    // 排序。
    // [65,60,80]->[60,65,80],如果是数组是使用Arrays.sort()。
    Collections.sort(films);
}

如果要从大到小排列,我们可以用Collections.reverse()方法,但该方法只能用于集合,JDK没有在Arrays类中实现与之对应的方法。 由于排序逻辑是写在类的内部,因此Comparable也叫做内部比较器。

Comparator

Comparable有两个很明显的缺陷,代码必须写在类的内部,并且只能按照固定的规则进行排序。如果我们无法修改类的内部或者有多种排序规则,那么Comparable接口就无能为力了,因此引入外部比较器Comparator解决上述问题。

public interface Comparator<T> {
    int compare(T o1, T o2);
    boolean equals(Object obj);
    // other methods
}

Comparator接口中声明了两个方法,一个是compare(),一个是equals(),由于Object类已经实现了equals()方法,而它又是所有类的父类,因此我们无需实现equals()方法,Comparator重新声明equals()方法仅仅是为了重写该方法的文档。compare()方法和ComparablecompareTo非常类似,如果compare(o1,o2)返回负值就表示o1o2小,返回零则表示两个对象相等,否则表示o1o2大。

我们用Comparator接口改写上面的代码:

public static void main(String[] args) {
    List<Film> films = new ArrayList<>();
    films.add(new Film(65));
    films.add(new Film(60));
    films.add(new Film(80));

    // 排序。
    // [65,60,80]->[60,65,80]。
    films.sort((o1, o2) -> o1.score - o2.score);
}