前言
对于Java对象,通常情况下只能存在==,!=的比较,而没有<或>的比较。但是实际开发中,我们却会遇到实现对象的排序,比如商品排序,按销量排序,价格排序,以及评论数排序等。可以通过java提供的两个比较器:Comparable和Comparator
Comparable接口
像String,包装类底层实现了Comparable接口,重写了compareTo(obj)方法并默认从小到大排序
- compareTo(obj)比较规则
如果当前对象this大于形参对象obj,则返回正整数
如果当前对象this小于形参对象obj,则返回负整数
如果当前对象this等于形参对象obj,则返回零
其实实际比较的还是对象之间的字段属性值比较,在宏观角度我们把它看做是对象之间的比较罢了,伪代码如下:
@Override
public int compareTo(obj) {
if(this.filed>obj.field){
return 1;
}else if(this.filed<obj.field){
return -1;
}else{
return 0;
}
}
自定义类实现Comparable接口
同理我们也可以自定义类实现Comparable接口来对自定义类进行排序,首先,自定义一个Student类:
/**
* 学生类
*/
public class Student implements Comparable<Student>{
private int id;
private String name;
public Student(int id,String name){
this.id=id;
this.name=name;
}
@Override
public int compareTo(Student o) {
//简写为三目运算
return (this.id>o.id?1:(this.id==o.id?(this.name.compareTo(o.name)):-1));
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
自定义Student类,并重写compareTo(),里面的方法体就是我们实现的比较逻辑,其中当id相等时,继续按照名字排序,由于String已经实现了compareTo方法,直接比较就行。OK,写完自定义类,继续来测试我们的排序方法,代码测试:
@Test
public void test(){
Student[]students=new Student[5];
students[0]=new Student(2019,"xf");
students[1]=new Student(2020,"aa");
students[2]=new Student(2030,"wz");
students[3]=new Student(2021,"zs");
students[4]=new Student(2016,"ls");
students[4]=new Student(2019,"af");
Arrays.sort(students); //实际调用compareTo()
System.out.println(Arrays.toString(students));
//[Student{id=2019, name='af'}, Student{id=2019, name='xf'}, Student{id=2020, name='aa'}, Student{id=2021, name='zs'}, Student{id=2030, name='wz'}]
}
通过打印我们看到,符合我们自定义的排序规则,同时称Comparable为自然排序,我们只需重写compareTo(),就实现了排序功能。是一种在类内部就定义好的排序,我们也称Comparable为内部比较器
Comparator接口,定制排序
当元素的类型没有实现java.lang.Comparable接口而且不方便修改代码,或者实现了java.lang.Comparable接口,但是已实现的排序规则不是我们想要的,那么可以用java.util.Comparator的对象来排序,强行对多个对象整体进行排序比较,所以称Comparator为定制排序。主要重写compare(T1,T2):如果方法返回正整数,则T1>T2;如果方法返回负整数,则T1<T2:如果返回零,则T1,T2相等,注:其中的T1,T2表示泛型,继续以上面的学生类为例:
//将学生数组按照id降序排序,若id相等,按照名字降序排序
@Test
public void test(){
Student[]students=new Student[5];
students[0]=new Student(2019,"xf");
students[1]=new Student(2020,"aa");
students[2]=new Student(2030,"wz");
students[3]=new Student(2021,"zs");
students[4]=new Student(2016,"ls");
students[4]=new Student(2019,"af");
Arrays.sort(students, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//重写排序逻辑
return -(s1.getId()>s2.getId()?1:(s1.getId()==s2.getId()?(s1.getName().compareTo(s2.getName())):-1));
}
});
System.out.println(Arrays.toString(students));
//[Student{id=2030, name='wz'}, Student{id=2021, name='zs'}, Student{id=2020, name='aa'}, Student{id=2019, name='xf'}, Student{id=2019, name='af'}]
可以代码看出,通过Comparator对象也可以实现对象的排序,而不用去改动原有的Student类,比较灵活,所以Comparator也称为外部比较器
总结
当某个类实现Comparable接口后,就表示此类具备了排序功能,任何地方的可以直接进行排序,可以理解为此类生而就有排序功能;而Comparator是在外部动态实现类的排序,需要用到类排序就new Comparator(T)即可。所以通常把Comparable看作是内部比较器,Comparator是外部比较器。