一. 概述
比较器Comparable 和 Comparator 都可以用来实现集合中元素的比较、排序。 Comparator位于包java.util下,而Comparable位于包java.lang下。Comparable接口将 比较代码嵌入自身类中,而Comparator在一个独立的类中实现比较。
众所周知,诸如Integer、String等这些基本类型的JAVA封装类都已经实现了 Comparable接口,这些类对象本身就支持自比较,可以通过 Collections.sort(和 Arrays.sort)就可以对元素进行排序,无需自己去实现Comparable接 口。对于大多数自定义的类的List序列,当这个对象不支持自比较或者自比较函数不能满 足需求时,我们可以写一个比较器来完成两个对象自己大小的比较,也就是指定使用 Comparator。如果不指定Comparator那么就需要使用自然规则排序,这里的自然顺序 就是实现Comparable接口设定的排序方式。
二. 代码示例
查看API可知,Comparable接口对实现它的每个类的对象强加一个整体排序。这个 排序被称为类的自然排序 ,类的compareTo方法被称为其自然比较方法。如果开发者 add进入一个Collection的对象想要Collections的sort方法帮你自动进行排序的话,那么 这个对象必须实现Comparable接口。Comparable也被称作内比较器,它的实现比较依 赖于compareTo方法。
compareTo方法的返回值是int,有三种情况: a) 比较者大于被比较者(也就是compareTo方法里面的对象),那么返回正整数 b) 比较者等于被比较者,那么返回0 c) 比较者小于被比较者,那么返回负整数
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
// Comparable 比较示例
// 定义一个Student类,实现Comparable接口并重写compareTo方法
public class Student implements Comparable
private String id;
private String username;
private Integer age;
// 省略了 set and get
public int compareTo(Student o) {
if ( this .age > o.getAge()) {
return 1 ;
} else if ( this .age < o.getAge()) {
return - 1 ;
} else {
return 0 ;
}
}
}
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
// 测试类 (测试Comparable比较器)
public class Test1 {
public static void main(String[] args) {
Student[] stu = new Student[ 3 ];
stu[ 0 ] = new Student( "1" , "zhangsan" , 11 );
stu[ 1 ] = new Student( "2" , "lisi" , 15 );
stu[ 2 ] = new Student( "3" , "wangwu" , 13 );
Arrays.sort(stu);
for ( int i = 0 ; i < stu.length; i++) {
System.out.println(stu[i].getId() + " "
+ stu[i].getUsername()
+ " " + stu[i].getAge());
}
}
}
|
查看API可知,Comparable强行对某个对象 collection 进行整体排序的比较函数。 可以将比较器Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允 许在排序顺序上实现精确控制。还可以使用 Comparator 来控制某些数据结构(如有 序 set或有序映射)的顺序,或者为那些没有自然顺序的对象 collection 提供排序。
Comparator接口里面有一个compare方法,方法有两个参数T o1和T o2,是泛型的表示 方式,分别表示待比较的两个对象,方法返回值和Comparable接口一样是int,有三种 情况: a) o1大于o2,返回正整数 b) o1等于o2,返回0 c) o1小于o3,返回负整数
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
// Comparator 比较示例
public class Test2 {
public static void main(String[] args) {
List new ArrayList<>();
stus.add( new Student( "1" , "zhengsan" , 11 ));
stus.add( new Student( "2" , "lisi" , 15 ));
stus.add( new Student( "3" , "wangwu" , 13 ));
Collections.sort(stus, new Comparator
@Override
public int compare(Student o1, Student o2) {
if (o1.getAge() > o2.getAge()) {
return 1 ;
} else if (o1.getAge() < o2.getAge()) {
return - 1 ;
} else {
return 0 ;
}
}
});
stus.forEach((Student stu) -> {
System.out.println(stu.getId() + " " + stu.getUsername() + " " + stu.getAge());
});
}
}
|
三. 差异比较
Comparable和Comparator的区别
参数 | Comparable | Comparator |
接口所在包 | java.lang.Comparable | java.util.Comparator |
排序逻辑 | 必须在待排序对象的类内部实现 | 排序逻辑在外部实现 |
实现方式 | 待排序对象的类内部实现Comparable 接口 | 调用时实现Comparator接 口 |
排序方法 | int compareTo(T o) | int compare(T o1, T o2) |
四. 优缺点:
优点:
1.Comparable被称为自然排序,如果使用者恰好需要数据遵循自然排序,完全不需要做 任何实现,直接调用Arrays.sort()就可以完成排序。
2.Comparator被称为外部排序,如果实现类没有实现Comparable接口或实现类里面的 排序不能满足要求,则可以实现Comparator去自定义比较器来写自己的算法。
缺点:
1.Comparable在实现类中必须实现其接口,耦合性比较高。如果算法要进行修改,实现 类必须进行修改维护起来也比较麻烦。
2.如果实现类没有实现任何排序,想要对自定义对象进行排序,Comparator必须自定义 比较器并写比较算法。 五. 总结
1.如果自定义的类需要对数据排序,最好根据需求来取舍是使用那一种或两种综合使用。
2.一般需要做比较的逻辑都可以使用的上Comparator,最常用的场景就是排序,排序常 使用Arrays和Collections的sort方法。排序时,两个对象比较的结果有三种:大于,等 于,小于。
3.如果实现类没有实现Comparable接口,又想对两个类对象进行比较(或者实现类实现了 Comparable接口,但是对compareTo方法内的比较算法不满意),那么可以实现 Comparator接口并自定义一个比较器,写比较算法。
4.实现Comparable接口的方式比实现Comparator接口的耦合性要强一些,如果要修改 比较算法就需要修改Comparable接口的实现类。如果说我们将实现类的.class文件打成 一个.jar文件提供给开发者使用的时候,每次改动就必须提供给使用者最新的.jar包,维 护起来很麻烦。实现Comparator的类是在外部进行比较的,不需要对实现类有任何修 改,使用起来就非常方便。