本帖最后由 小江哥 于 2019-2-26 21:40 编辑
一. 概述
比较器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) 比较者小于被比较者,那么返回负整数
[Java] 纯文本查看 复制代码 // Comparable 比较示例
// 定义一个Student类,实现Comparable接口并重写compareTo方法
public class Student implements Comparable<Student> {
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;
}
}
}[Java] 纯文本查看 复制代码 // 测试类 (测试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,返回负整数
[Java] 纯文本查看 复制代码 // Comparator 比较示例
public class Test2 {
public static void main(String[] args) {
List<Student> stus = 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<Student>() {
@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的类是在外部进行比较的,不需要对实现类有任何修 改,使用起来就非常方便。
|