Comparable 和 Comparator 接口都是用来比较大小的,首先来看一下 Comparable 的定义:
package java.lang;
import java.util.*;
public interface Comparable<T> {
public int compareTo(T o);
}
Comparator的定义如下:
package java.util;
public interface Comparator<T> {
int compare(T o1, T o2);
}
Comparable对实现它的每个类的对象进行整体排序。这个接口需要类本身去实现。若一个类实现了Comparable 接口,实现 Comparable 接口的类的对象的 List 列表 ( 或数组)可以通过 Collections.sort(或 Arrays.sort)进行排序。
举例(类Person1实现了Comparable接口)
public class Person1 implements Comparable<Person1> {
private int age;
private String name;
public Person1(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person1 o) {
return this.age - o.age;
}
@Override
public String toString() {
return name+":"+age;
}
}
可以看到 Person1 实现了 Comparable 接口中的 compareTo 方法。实现Comparable 接口必须修改自身的类,即在自身类中实现接口中相应的方法。
而 compareTo(Person1 o) 的返回值 是 this.age - o.age
的结果,决定了最后的排序结果是 升序(从左到右的方向上,数据从小到大) 还是 降序(从左到右的方向上,数据从大到小)。
compareTo 方法中的参数:Person1 o
表示被比较的对象,而 Person1 自身的类 是主动比较的对象。
通俗的讲,就是 “我” 要和 “谁” 比较,this.age
表示“我”,o.age
表示“谁”,即被比较的对象;
如果返回值 是 正数,即 this.age
大于 o.age
,则让 this.age
即“我”排在后面,“o.age” 即 被比较的对象 排在前面,从排序结果来看 就是 升序;
如果返回值 是 负数,即 this.age
小于 o.age
,则让 this.age
即“我”排在前面,“o.age” 即 被比较的对象 排在后面,从排序结果来看 还是 升序;
一句话总结:
如果返回值为正,则把主动比较的值放后面;
如果返回值为负,则把主动比较的值放前面。
通过上面的总结,如果想让排序的结果表现为 降序,则要把 compareTo 方法中的代码改为:return o.age - this.age
,再简单分析下:如果 o.age 大于 this.age,则返回值为正,要把主动比较的值 this.age 放在后面,this.age 是较小的值,而它放在了后面,最终的排序结果即是 降序;反之 o.age 小于 this.age,返回值为负,this.age 放前面,this.age 较大且放在前面,最终结果还是降序。
(貌似讲 返回值决定顺序的 ,笔者讲的是全网最详细的了有木有?还有谁!)
测试代码:
Person1 person1 = new Person1("zzh",18);
Person1 person2 = new Person1("jj",17);
Person1 person3 = new Person1("qq",19);
List<Person1> list = new ArrayList<>();
list.add(person1);
list.add(person2);
list.add(person3);
System.out.println(list);
Collections.sort(list);
System.out.println(list);
输出结果:
[zzh:18, jj:17, qq:19]
[jj:17, zzh:18, qq:19]
如果我们的这个类无法修改,这就用到了Comparator这个接口:
public final class Person2 {
private int age;
private String name;
public Person2(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + ":" + age;
}
}
如类Person2,这个类已经固定,无法进行对其类自身的修改,也修饰词final了,你也别想 implements Comparable,那么此时怎么办呢?在类的外部使用 Comparator的接口。如下测试代码:
Person2 p1 = new Person2("zzh",18);
Person2 p2 = new Person2("jj",17);
Person2 p3 = new Person2("qq",19);
List<Person2> list2 = new ArrayList<Person2>();
list2.add(p1);
list2.add(p2);
list2.add(p3);
System.out.println(list2);
Collections.sort(list2,new Comparator<Person2>() {
@Override
public int compare(Person2 o1, Person2 o2) {
return o1.getAge() - o2.getAge();
}
});
System.out.println(list2);
输出结果:
[zzh:18, jj:17, qq:19]
[jj:17, zzh:18, qq:19]
上面讲到 Comparable 的 compareTo 方法的返回值 决定排序结果,而 Comparator 是根据 compare 方法的返回值 决定排序结果。它们俩的排序逻辑是一样一样滴~。compare 方法中的参数,第一个参数 是主动比较的值,第二个参数 是被比较的值。
总结
Comparable 是排序接口;若一个类实现了 Comparable 接口,就意味着 “该类支持排序”。而 Comparator 是比较器;我们若需要控制某个类的次序,可以建立一个 “该类的比较器” 来进行排序。
前者应该比较固定,和一个具体类相绑定,而后者比较灵活,它可以被用于各个需要比较功能的类使用。可以说前者属于 “静态绑定”,而后者可以 “动态绑定”。
我们不难发现:Comparable 相当于 “内部比较器”,而 Comparator 相当于 “外部比较器”。