Comparable定義:
- Comparable是一個(gè)排序接口,當(dāng)一個(gè)類(lèi)實(shí)現(xiàn)了該接口,就意味著“該類(lèi)支持排序”。
具體實(shí)現(xiàn):
package java.lang;
import java.util.*;
public interface Comparable<T> {
public int compareTo(T o);
}
我們可以看到它是通過(guò)compareTo方法來(lái)進(jìn)行排序的。
假設(shè)我們通過(guò) x.compareTo(y) 來(lái)“比較x和y的大小”。
若返回“負(fù)數(shù)”,意味著“x比y小”;返回“零”,意味著“x等于y”;返回“正數(shù)”,意味著“x大于y”。
Comparator定義:
- Comparator為比較器接口,若要實(shí)現(xiàn)某個(gè)本身不支持排序的類(lèi),可以通過(guò)定義定義一個(gè)Comparator接口來(lái)實(shí)現(xiàn)類(lèi)的排序。
具體實(shí)現(xiàn):
package java.util;
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
- 若一個(gè)類(lèi)要實(shí)現(xiàn)Comparator接口:它一定要實(shí)現(xiàn)compareTo(T o1, T o2) 函數(shù),但可以不實(shí)現(xiàn) equals(Object obj) 函數(shù)。
為什么可以不實(shí)現(xiàn) equals(Object obj) 函數(shù)呢?
因?yàn)槿魏晤?lèi),默認(rèn)都是已經(jīng)實(shí)現(xiàn)了equals(Object obj)的。 Java中的一切類(lèi)都是繼承于java.lang.Object,在Object.java中實(shí)現(xiàn)了equals(Object obj)函數(shù);所以,其它所有的類(lèi)也相當(dāng)于都實(shí)現(xiàn)了該函數(shù)。
- int compare(T o1, T o2) 是“比較o1和o2的大小”。返回“負(fù)數(shù)”,意味著“o1比o2小”;返回“零”,意味著“o1等于o2”;返回“正數(shù)”,意味著“o1大于o2”。
Comparable和Comparator的比較:
共同點(diǎn):Comparable & Comparator 都是用來(lái)實(shí)現(xiàn)集合中元素的比較、排序的。當(dāng)我們定義的某個(gè)類(lèi)需要進(jìn)行排序時(shí),就要考慮實(shí)現(xiàn)Comparable或Comparator接口。
我們定義一個(gè)Person,要求其根據(jù)id進(jìn)行排序:
實(shí)現(xiàn)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();
}
}
輸出結(jié)果:
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類(lèi)中實(shí)現(xiàn)了Comparable接口,并重寫(xiě)了CompareTo方法。
實(shí)現(xiàn)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);
//調(diào)用sort函數(shù),并傳入自定義Comparator
Collections.sort(list,new MyComparator());
System.out.println("After sort:");
printList(list);
}
//自定義Comparator接口,并重寫(xiě)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();
}
}
通過(guò)上面的兩種實(shí)現(xiàn)方式:
區(qū)別:
- Comparable接口是在集合內(nèi)部定義的方法實(shí)現(xiàn)的排序。
- Comparator接口是在集合外部實(shí)現(xiàn)的排序。
- 簡(jiǎn)單來(lái)說(shuō),comparable接口是通過(guò)類(lèi)自己完成比較,而comparator接口是通過(guò)外部程序?qū)崿F(xiàn)比較。
若同時(shí)實(shí)現(xiàn)Comparable接口和Comparator接口,排序會(huì)聽(tīng)哪個(gè)的呢?
我們?cè)O(shè)置Comparable接口實(shí)現(xiàn)升序,而Comparator接口實(shí)現(xiàn)降序。
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);
//調(diào)用sort函數(shù),并傳入自定義Comparator
Collections.sort(list,new MyComparator());
System.out.println("After sort:");
printList(list);
}
//自定義Comparator接口,并重寫(xiě)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();
}
}
輸出結(jié)果:
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 /
我們可以看到,最后的結(jié)果是以降序方式輸出的。也就意味著comparator接口優(yōu)先于comparable接口。
實(shí)際上,對(duì)于sort排序方法,若傳入自定義的comparator接口,則會(huì)以傳入的comparator方法來(lái)實(shí)現(xiàn)排序,否則,會(huì)使用類(lèi)本身的comparable接口方法。
何時(shí)使用comparable,何時(shí)使用comparator?
- 若我們?cè)趯?duì)要排序的類(lèi)的排序規(guī)則比較固定,也就是不常修改時(shí),我們考慮實(shí)現(xiàn)comparable接口。
- 若我們對(duì)要排序的類(lèi)的排序規(guī)則是經(jīng)常變化的,那么我們考慮實(shí)現(xiàn)comparator接口。