Comparator和Comparable的区别以及使用
Java基础之comparator和comparable的区别以及使用
Comparable
Comparable
定义在java.lang
包里,意味着可以被比较的能力,因此某个类想要可以被排序,被比较大小,需要实现这个接口.
public int compareTo(T o);
接口里只定义了这一个方法, 代表了: 传入一个对象, 将对象和元素自身进行比较, 如果元素自身大, 返回 1, 相等返回 0, 元素自身小于参数则返回 - 1
例如:
private static class Student implements Comparable {
int id;
String name;
int age;
@Override
public int compareTo(Object o) {
return this.id - ((Student) o).id;
}
}
代码中定义了Student
类,以及实现了 Comparable
, 即只比较他们的 id 的大小即可
Comparator
Comparator
定义与java.util
包中, 代表着一个角色,这个角色的功能是对传入的两个元素进行大小的比较,并且返回结果.
int compare(T o1, T o2);
这是最主要的一个方法,我们需要传入两个同一类型的元素.
使用示例:
private static class StudentCom1 implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.id - o2.id;
}
}
代码中定义了一个Student的比较器,实现了Comparator
区别及联系
那么问题来了,都有 Comparable
了, 还要Comparator
干什么?
设想一个场景,我们定义了一个学生类,如上面代码所示,那么学生可以按着id的大小进行排序.
然后现在有两个使用的地方,第一个是考试,需要学生按照id排序.第二个是学生统计,需要学生按照年龄进行排序.
怎么实现两种完全不同的排序方式呢?或者更极端一点,一会需要按照id增序,一会需要按照id降序呢?改源代码肯定是不科学的.
这个时候就可以采用以下方案:
- 学生实现自然排序,即最通用的那种排序方式,比如按照id增序.
- 实现几个不同的比较器,比如
运动会比较器
,吃饭比较器
等等. - 在需要默认排序的情况下,直接调用学生的
comparTo
即可. - 在特定情景下,调用集合类的排序方法,传入一个想要的比较器即可 Collections.sort(List<T> list,Comparator<? super T> c);
Comparator使用
单一条件排序:
List<Student> stus = new ArrayList<Student>(){
{
add(new Student("张三", 30));
add(new Student("李四", 20));
add(new Student("王五", 60));
}
};
//对users按年龄进行排序
Collections.sort(stus, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 升序
//return s1.getAge()-s2.getAge();
return s1.getAge().compareTo(s2.getAge());
// 降序
// return s2.getAge()-s1.getAge();
// return s2.getAge().compareTo(s1.getAge());
}
});
// 输出结果
...
还可以使用lambda表达式简化代码, 前提是JDK8开发环境, 如下:
List<Student> stus = new ArrayList<Student>(){
{
add(new Student("张三", 30));
add(new Student("李四", 20));
add(new Student("王五", 60));
}
};
//对users按年龄进行排序
Collections.sort(stus, (s1,s2)->(s1.getAge()-s2.getAge()));
多条件排序:
List<Student> stus = new ArrayList<Student>(){
{
add(new Student("张三", 30, 1));
add(new Student("李四", 20, 2));
add(new Student("王五", 40, 3));
add(new Student("赵六", 30, 4));
add(new Student("陈七", 40, 5));
add(new Student("周八", 20, 6));
}
};
Collections.sort(stus, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int flag;
// 首选按年龄升序排序
flag = s1.getAge()-s2.getAge();
if(flag==0){
// 再按学号升序排序
flag = s1.getNum()-s2.getNum();
}
return flag;
}
});
System.out.println("年龄 学号 姓名 ");
for(Student s : stus){
System.out.println(s.getAge()+" "+s.getNum()+" "+s.getName());
}
自定义条件排序
String[] order = {"语文","数学","英语","物理","化学","生物","政治","历史","地理","总分"};
final List<String> definedOrder = Arrays.asList(order);
List<String> list = new ArrayList<String>(){
{
add("总分");
add("英语");
add("政治");
add("总分");
add("数学");
}
};
Collections.sort(list,new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int io1 = definedOrder .indexOf(o1);
int io2 = definedOrder .indexOf(o2);
return io1-io2;
}
});
for(String s:list){
System.out.print(s+" ");
}
使用lambda表达式简化代码:
Collections.sort(list, (o1, o2)->(definedOrder .indexOf(o1)-definedOrder .indexOf(o2)));
总结
他们的区别是角色不同,想要实现的目的也不同.一个是内部自然排序,只能有一种定义.一个是外部的比较器,可以定义多个不同的比较器,按需取用.
唯一的联系可能就是他们最终都是对两个元素定义一个孰大孰小?