Java Comparable 和 Comparator
关于Comparable和Comparator
这篇文章参考Java Sorting: Comparator vs Comparable Tutorial和Java排序: 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型的值,意义如下(大小都是逻辑上的大小):- positive – o1 的值比 o2大
- zero – o1 的值和 o2 一样大
- 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
因为它把排序机制和数据结构分离开来了,这样代码比较容易维护。