Java Comparable 和 Comparator 关于Comparable和Comparator

这篇文章参考Java Sorting: Comparator vs Comparable TutorialJava排序: Comparator vs Comparable 入门做了一些个人总结。

Comaprable

一个实现了comparable接口的对象的实例可以被用于和相同对象的不同实例做对比。它本身必须实现java.lang.Comparable的接口,这样它就拥有了对比的能力。即实现了Comparable的对象具有对比的能力。

Comparator

一个Comparetor对象能够对比不同的对象,它比较的不是自身的对象——Comparator本身,而是对比其他类的对象。一个Comparator对象必须实现java.util.Comparator接口。

如何使用

在Java中有两个接口来支持这两个概念(Comparable和Comparator),这两个接口都有连个需要被实现的方法。分别是:
* java.lang.Comparable: int comparaTo(Object o1)
该方法将该对象(this)和o1进行对比,返回一个int型的值,意义如下(大小都是逻辑上的大小):
1. positive – 该对象比o1大
2. zero – 该对象和o1对象一样大
3. negative – 该对象比o1对象小

  • java.util.Comparator: int compare(Object o1, Object o2)
    该方法将o1和o2进行比较,返回一个int型的值,意义如下(大小都是逻辑上的大小):

    1. positive – o1 的值比 o2大
    2. zero – o1 的值和 o2 一样大
    3. negative – o1 的值比 o2小
  • java.util.Collections.sort(List)java.util.Arrays.sort(Object [])这两个方法用把指定的list按照升序排列,这时list中的元素必须实现java.lang.Comparable接口.

  • java.util.Collections.sort(List,Comparator)java.util.Arrays.sort(Object[], Comparator)这两个方法在能够提供Comparator时对list进行排序。

举个栗子

考虑一个web页面需要显示职工的列表。通常情况下职工列表是按照职工的ID来排序。同样也可以根据姓名或者年龄来排序。
我们默认的条件是员工的排序是按照职工的ID来进行排序的,下面的代码省略了各种import,不可直接粘贴代码运行

class Employee implements Comparable<Employee> { // 职工的类
    private int id;
    private String name;
    private int age;

    public int compareTo(Employee e) {
        return this.getId() - e.getId();
    }

    public Employee(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public int getId(){return this.id;}
    public String getName(){return this.name;}
    public int getAge(){return this.age;}
}

下面我们将使用一个工具类来构造一个Employees List

class Util {
    public static List<Employee> getEmployee() {
        List<Employee> col = new ArrayList<Employee>();
        col.add(new Employee(5, "Frank", 28));
        col.add(new Employee(1, "Jorge", 19));
        col.add(new Employee(6, "Bill", 34));
        col.add(new Employee(3, "Michel", 10));
        col.add(new Employee(7, "Simpson", 8));
        col.add(new Employee(4, "Clerk", 16));
        col.add(new Employee(8, "Lee", 40));
        col.add(new Employee(2, "Mark", 30));

        return col;
    }
}

接下来是Main方法

public class Main {

    public static void main(String[] args) {
        List<Employee> coll =Util.getEmployee();
        Collections.sort(coll);
        for(Employee e: coll){
            System.out.println(e.getId() + " " + e.getName() + " " + e.getAge());
        }
    }
}

输出结果将如下所示
1 Jorge 19
2 Mark 30
3 Michel 10
4 Clerk 16
5 Frank 28
6 Bill 34
7 Simpson 8
8 Lee 40

根据其他字段排序

如果我们要根据employee的其他字段进行排序,上面的例子我们就要修改Employee的compareTo的实现,这样必然会破坏我们按照id进行排序的机制。其实最好的方法就是将排序策略与模型分离开来,这是Comparator就派上用场了。
下面的代码通过构建一个内部类将coll根据Employee的name升序排列。其实只需稍微修改Main方法。

public class Main {

    public static void main(String[] args) {
        List<Employee> coll =Util.getEmployee();

        Comparator<Employee> cmp = new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                return o1.getName().compareTo(o2.getName());
            }
        };

        Collections.sort(coll, cmp);
        for(Employee e: coll){
            System.out.println(e.getId() + " " + e.getName() + " " + e.getAge());
        }
    }
}

输出结果如下:
6 Bill 34
4 Clerk 16
5 Frank 28
1 Jorge 19
8 Lee 40
2 Mark 30
3 Michel 10
7 Simpson 8

同样的可以按照这种方法对id进行重排序

其实本人是比较喜欢Comparator因为它把排序机制和数据结构分离开来了,这样代码比较容易维护。