Comparable定义:
- Comparable是一个排序接口,当一个类实现了该接口,就意味着“该类支持排序”。
具体实现:
package java.lang;
import java.util.*;
public interface Comparable<T> {
public int compareTo(T o);
}
我们可以看到它是通过compareTo方法来进行排序的。
假设我们通过 x.compareTo(y) 来“比较x和y的大小”。
若返回“负数”,意味着“x比y小”;返回“零”,意味着“x等于y”;返回“正数”,意味着“x大于y”。
Comparator定义:
- Comparator为比较器接口,若要实现某个本身不支持排序的类,可以通过定义定义一个Comparator接口来实现类的排序。
具体实现:
package java.util;
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
- 若一个类要实现Comparator接口:它一定要实现compareTo(T o1, T o2) 函数,但可以不实现 equals(Object obj) 函数。
为什么可以不实现 equals(Object obj) 函数呢?
因为任何类,默认都是已经实现了equals(Object obj)的。 Java中的一切类都是继承于java.lang.Object,在Object.java中实现了equals(Object obj)函数;所以,其它所有的类也相当于都实现了该函数。
- int compare(T o1, T o2) 是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”。
Comparable和Comparator的比较:
共同点:Comparable & Comparator 都是用来实现集合中元素的比较、排序的。当我们定义的某个类需要进行排序时,就要考虑实现Comparable或Comparator接口。
我们定义一个Person,要求其根据id进行排序:
实现Comparable接口
public class Person implements Comparable<Person>{
private int id;
private String name;
private int age;
public Person(int id,String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person o) {
return this.id - o.id;
}
@Override
public String toString() {
return "id: " + id + " name: " + name + " age: " + age;
}
public static void main(String[] args){
List<Person> list = new ArrayList<>();
list.add(new Person(3,"John",18));
list.add(new Person(1,"Marry",21));
list.add(new Person(2,"Tom",20));
System.out.println("Before sort:");
printList(list);
Collections.sort(list);
System.out.println("After sort:");
printList(list);
}
public static void printList(List<Person> list){
for (Person p : list){
System.out.print(p + " / ");
}
System.out.println();
}
}
输出结果:
Before sort:
id: 3 name: John age: 18 / id: 1 name: Marry age: 21 / id: 2 name: Tom age: 20 /
After sort:
id: 1 name: Marry age: 21 / id: 2 name: Tom age: 20 / id: 3 name: John age: 18 /
我们可以看到person类中实现了Comparable接口,并重写了CompareTo方法。
实现Comparator接口
public class Person{
private int id;
private String name;
private int age;
public Person(int id,String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "id: " + id + " name: " + name + " age: " + age;
}
public static void main(String[] args){
List<Person> list = new ArrayList<>();
list.add(new Person(3,"John",18));
list.add(new Person(1,"Marry",21));
list.add(new Person(2,"Tom",20));
System.out.println("Before sort:");
printList(list);
//调用sort函数,并传入自定义Comparator
Collections.sort(list,new MyComparator());
System.out.println("After sort:");
printList(list);
}
//自定义Comparator接口,并重写compare方法
private static class MyComparator implements Comparator<Person>{
@Override
public int compare(Person o1, Person o2) {
return o1.id - o2.id;
}
}
private static void printList(List<Person> list){
for (Person p : list){
System.out.print(p + " / ");
}
System.out.println();
}
}
通过上面的两种实现方式:
区别:
- Comparable接口是在集合内部定义的方法实现的排序。
- Comparator接口是在集合外部实现的排序。
- 简单来说,comparable接口是通过类自己完成比较,而comparator接口是通过外部程序实现比较。
若同时实现Comparable接口和Comparator接口,排序会听哪个的呢?
我们设置Comparable接口实现升序,而Comparator接口实现降序。
public class Person implements Comparable<Person>{
private int id;
private String name;
private int age;
public Person(int id,String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person o) {
return id - o.id;
}
@Override
public String toString() {
return "id: " + id + " name: " + name + " age: " + age;
}
public static void main(String[] args){
List<Person> list = new ArrayList<>();
list.add(new Person(3,"John",18));
list.add(new Person(1,"Marry",21));
list.add(new Person(2,"Tom",20));
System.out.println("Before sort:");
printList(list);
//调用sort函数,并传入自定义Comparator
Collections.sort(list,new MyComparator());
System.out.println("After sort:");
printList(list);
}
//自定义Comparator接口,并重写compare方法
private static class MyComparator implements Comparator<Person>{
@Override
public int compare(Person o1, Person o2) {
return o2.id - o1.id;
}
}
private static void printList(List<Person> list){
for (Person p : list){
System.out.print(p + " / ");
}
System.out.println();
}
}
输出结果:
Before sort:
id: 3 name: John age: 18 / id: 1 name: Marry age: 21 / id: 2 name: Tom age: 20 /
After sort:
id: 3 name: John age: 18 / id: 2 name: Tom age: 20 / id: 1 name: Marry age: 21 /
我们可以看到,最后的结果是以降序方式输出的。也就意味着comparator接口优先于comparable接口。
实际上,对于sort排序方法,若传入自定义的comparator接口,则会以传入的comparator方法来实现排序,否则,会使用类本身的comparable接口方法。
何时使用comparable,何时使用comparator?
- 若我们在对要排序的类的排序规则比较固定,也就是不常修改时,我们考虑实现comparable接口。
- 若我们对要排序的类的排序规则是经常变化的,那么我们考虑实现comparator接口。