一:Comparable
排序接口,相当于实现了该类接口就可赋予类一个排序属性。
可以看出,该接口的类型为泛型,也就是说T的位置既可以有自定义类型,又可以有原有的类型。
里面只有一个函数,因此继承该接口的类都必须重写这个函数compareTo()
示例:学生类,先根据年龄排序,再根据name排序。
package day_10;
public class student implements Comparable<student> {
int age;
String name;
student(int age,String name){
this.age=age;
this.name=name;
}
//compareTo函数重写
@Override
public int compareTo(student s){
int num=this.age-s.age; //这是降序,升序的话就改成s.age-this.age
return num==0?this.name.compareTo(s.name):num;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
student student = (student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = age;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
@Override
public String toString(){
return "student{age="+age+",name='"+name+"'};";
}
}
二:Comparator
比较器接口,相当于实现了该接口之后就能实现一个比较器。比较器是实实在在存在的,可以类似于参数一样进行传递。
package day_10;
//必须导包
import java.util.Comparator;
//下面就是一个自定义的排序类
public class comparator implements Comparator<student> {
@Override
public int compare(student s1, student s2){
int num=s1.age-s2.age;
return num==0?s1.name.compareTo(s2.name):num;
}
}
//在主类中调用
TreeSet<student> treeSet = new TreeSet<student>(new comparator());//匿名对象
或
comparator c1=new comparator();
TreeSet<student> treeSet = new TreeSet<student>(c1);
写成匿名类的形式:
TreeSet<student> treeSet = new TreeSet<student>(new Comparator<student>() {
@Override
public int compare(student s1, student s2) {
int num = s1.age - s2.age;
return num == 0 ? s1.name.compareTo(s2.name) : num;
}
});
这个一看就能发现这个可以省去好多重复操作,比如有多个类排序操作一样,就没必要在每个类中都实现一次Comparable接口,只需要写一个比较器,然后像传参数一样传递其即可。
例二:
ArrayList<student>arrayList=new ArrayList<student>();
arrayList.add(stu1);
Collections.sort(arrayList,c1);
三:优劣相比
一些场景下二者可以混合使用。并且二者都是接口。
用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是使用Comparable的话还得破开类的代码,这就违反了开闭原则。
用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑(因为这个接口里有很多函数功能),使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。