但是,当需要排序的集合或数组不是单纯的数字类型时,我们通常使用Comparator或Comparable,以简单的方式实现对象排序或自定义排序。
1.Comparable:内部比较器,此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo 方法被称为它的自然比较方法。
2.Comparator:外部比较器,是T - 此 Comparator 可以比较的对象类型,它是强行对某个对象collection 进行整体排序 的比较函数。
3.区别:
Comparable 用作默认的比较方式 。
Comparator 用作自定义的比较方式,当默认的比较方式不适用时或者没有提供默认的比较方式,使用Comparator就非常有用。
Comparator 强行对某个对象collection进行整体排序的比较函数,可以将Comparator传递给Collections.sort或Arrays.sort。
Comparable强行对实现它的每个类的对象进行整体排序,实现此接口的对象列表(和数组)可以通过Collections.sor或Arrays.sort进行自动排序。
4.用法:
1、内部比较器:java.lang.Comparable<T> 接口声明了:int compareTo(T o) 方法
比较此对象与执行对象的顺序。比较规则同上,即:
1)如果此对象大于指定对象,返回正整数 ;
2)如果此对象小于指定对象,返回负整数 ;
3)如果此对象等于指定对象,返回零 。
2、外部比较器:java.util.Comparator<T> 接口声明了: int compare<T o1, T o2> 方法
比较用来排序的两个参数:
1)如果o1大于o2,则返回正整数;
2)如果o1小于o2,则返回负整数 ;
3)如果o1等于o2,则返回零 。
这里我们使用TreeSet来举例说明:
1.先定义一个学生类:在学生类实现内部比较器(Comparable)接口,我们需要重写int compareTo(T o) 方法。这里我们是对学生成绩排序。double是基本数据类型,这里我们操作的是对象,需要对double进行装箱。
public class Student implements Comparable<Student> {
String name;// 姓名
int age;// 年龄
double score;// 成绩
public Student() {
}
public Student(String name, int age, double score) {
super();
this.name = name;
this.age = age;
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", score=" + score + "]";
}
@Override
public int compareTo(Student o) {
Double double1 = new Double(this.score);
Double double2 = new Double(o.getScore());
return double1.compareTo(double2);
}
}
调用方法;
import java.util.Comparator;
import java.util.TreeSet;
public class Test01 {
public static void main(String[] args) {
Student stu1 = new Student("一大大", 20, 88.5);
Student stu2 = new Student("二大大", 21, 88);
Student stu3 = new Student("三大大", 18, 89);
//1.内部比较器 eg:成绩排序
TreeSet<Student> treeSet1 = new TreeSet<Student>();
treeSet1.add(stu1);
treeSet1.add(stu2);
treeSet1.add(stu3);
showStudent(treeSet1);
}
public static void showStudent(TreeSet<Student> students) {
for (Student student : students) {
System.out.println(student);
}
}
}
输出结果:
Student [name=二大大, age=21, score=88.0]
Student [name=一大大, age=20, score=88.5]
Student [name=三大大, age=18, score=89.0]
2.使用外部比较器(Comparator)来实现:先定义一个外部比较器的方法来实现接口Comparator,重写 int compare<T o1, T o2> 方法 ,这里我们来比较年龄。
class ageComp implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.age - o2.age;
}
}
调用方法:
//2.外部比较器 eg:年龄排序
Comparator<Student> comparator = new ageComp();
TreeSet<Student> treeSet2 = new TreeSet<>(comparator);
treeSet2.add(stu1);
treeSet2.add(stu2);
treeSet2.add(stu3);
showStudent(treeSet2);
输出结果:
Student [name=三大大, age=18, score=89.0]
Student [name=一大大, age=20, score=88.5]
Student [name=二大大, age=21, score=88.0]
3.当然,我们还可以用匿名内部类来写Comparator:这里我们来按名字排序。
//3.外部比较器内部类 eg:姓名排序
TreeSet<Student> treeSet3 = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
});
treeSet3.add(stu1);
treeSet3.add(stu2);
treeSet3.add(stu3);
showStudent(treeSet3);
输出结果:
Student [name=一大大, age=20, score=88.5]
Student [name=三大大, age=18, score=89.0]
Student [name=二大大, age=21, score=88.0]
最后,总结一下两种比较器的区别:
1)如果使用内部比较器,需要比较的对象必须要实现Comparable接口,并重写compareTo( T o)方法,否则不能直接使用Collections中的sort方法,程序会报错。因为程序不知道你要以何种方式来进行比较。
2)使用外部比较器,需要自己写一个比较器实现Comparator接口,并实现compare(T o1, T o2)方法,根据自己的需求定义比较规则。使用外部比较器这种方式比较灵活。