比较器
对象之间的比较
- 自然排序:
public interface Comparable<T>
- 自定义排序:
public interface Comparator<T>
自然排序
- 对于实现了
Comparable
接口的类,都会实现public int compareTo(T o)
方法(接口中只有这一个类)。 - 不能和
null
比较,因为相比较的两者必须都是类对象 Java
的core class
除了java.math.BigDecimal
这个类都默认实现了Comparable
接口- 实现了
Comparable
接口的类的实例组成的数组可以通过Collections
和Arrays
中的sort()
方法进行排序——对于实现该接口类的两个实例对象a1,a2:
- 如果
a1.compareTo(a2) == 0
,那么表示二者相等;特别需要注意的是:通常情况下建议判等的结果应该和equals()
结果一致 - 如果
a1.compareTo(a2) < 0
返回小于0的整数,表示小于 - 如果
a1.compareTo(a2)> 0
返回大于0的整数,表示大于
- 如果
- 总之就是为了给排序函数提供一个比较大小的依据,需要进行排序的自定义类通过重写
compareTo()
方法将大小和正负零进行对应即可
自定义排序
- 不是让待排序的类实现的,是作为形参使用的,所以不会影响原先实现的排序
- 和
Comparable
接口不同的是除了抽象方法compare(T o1, T o2)
之外还提供了很多默认方法 - 当自定义类实现
Comparable
接口而又不方便修改代码, 或者实现了Comparable
接口的排序规则不适合当前的操作,只是想在这异步操作中使用这排序规则,就可以用Comparator
接口实现 - 实现方法
compare(T o1, T o2)
有两个参数,表示相比较的两个元素,和Comparable
接口中的compareTo(T o1)
单参数(默认是this
和o1
相比)不同。 - 返回值大小和正负零的对应和
Comparable
接口的实现一致 - 将
Comparator
作为参数传递给sort
方法(如Collections.sort 或 Arrays.sort
), 从而允许在排序顺序上实现调用时自定义
举例
自然排序
class Student implements Comparable{//实现Comparable接口的自定义类
String name;
int number;
public Student() {
}
public Student(String name, int number) {
this.name = name;
this.number = number;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", number=" + number +
'}';
}
@Override
public int compareTo(Object o) {//重写compareTo()方法,根据number变量排序
if(o instanceof Student){
Student stmp = (Student)o;
if(this.number > ((Student) o).number)
return 1;
else if(this.number < ((Student) o).number)
return -1;
else
return 0;
}
throw new RuntimeException("类型不匹配");
}
}
public class CompareTest {
public static void main(String[] args) {
ArrayList<Student> arrayList = new ArrayList<>();
Student s1 = new Student("Student1",1 );
Student s2 = new Student("Student2",2 );
Student s3 = new Student("Student3",3 );
arrayList.add(s3);arrayList.add(s2);arrayList.add(s1);//逆序添加
Collections.sort(arrayList);//排序,过程中会调用compareTo()方法
for(Student s : arrayList)
System.out.println(s);
}
}
结果输出:
自定义排序
还是在上面例子中新增score
成员变量,想在某次排序中根据学生的成绩进行排序而不用它默认的排序
class Student implements Comparable{
String name;
int number;
int score;
public Student() {
}
public Student(String name, int number,int score) {
this.name = name;
this.number = number;
this.score = score;//新增score变量
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", number=" + number +
", score=" + score +
'}';
}
@Override
public int compareTo(Object o) {//注意这时候定义的自然排序还是保留
if(o instanceof Student){
Student stmp = (Student)o;
if(this.number > ((Student) o).number)
return 1;
else if(this.number < ((Student) o).number)
return -1;
else
return 0;
}
throw new RuntimeException("类型不匹配");
}
}
public class CompareTest {
public static void main(String[] args) {
ArrayList<Student> arrayList = new ArrayList<>();
Student s1 = new Student("Student1",1 ,69);
Student s2 = new Student("Student2",2 ,85);
Student s3 = new Student("Student3",3 ,60);
arrayList.add(s3);arrayList.add(s2);arrayList.add(s1);//逆序添加
Collections.sort(arrayList, new Comparator<Student>() {//自定义比较器实现成绩的倒序输出
@Override
public int compare(Student o1, Student o2) {
if(o1.score < o2.score)
return 1;
else if(o1.score > o2.score)
return -1;
else
return 0;
}
});
for(Student s : arrayList)
System.out.println(s);
}
}
结果输出
注意的是:按照通常意义上的大于小于相等对应正整数,负整数和零的话,排序结果就是从“小”到“大”,所以底层逻辑一定是按照返回值的负零正排序的;如果想要从“大”到“小”排序,就大于对等负数,以此类推
常用类中的体现
(正好做到一个相关优先队列的问题,翻看源码看到PriorityQueue
中元素就是默认是按照自然排序排列(底层用的是二叉树小顶堆实现,不是链表)的(也可以自定义Comparator
),但是不能用iterator
对象遍历,poll()
出才是排序后的结果)