Comparable定義:
- Comparable是一個排序接口梗逮,當(dāng)一個類實(shí)現(xiàn)了該接口哎榴,就意味著“該類支持排序”桥温。
具體實(shí)現(xiàn):
package java.lang;
import java.util.*;
public interface Comparable<T> {
public int compareTo(T o);
}
我們可以看到它是通過compareTo方法來進(jìn)行排序的跛璧。
假設(shè)我們通過 x.compareTo(y) 來“比較x和y的大小”纬向。
若返回“負(fù)數(shù)”,意味著“x比y小”渣磷;返回“零”婿着,意味著“x等于y”;返回“正數(shù)”醋界,意味著“x大于y”竟宋。
Comparator定義:
- Comparator為比較器接口,若要實(shí)現(xiàn)某個本身不支持排序的類形纺,可以通過定義定義一個Comparator接口來實(shí)現(xiàn)類的排序丘侠。
具體實(shí)現(xiàn):
package java.util;
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
- 若一個類要實(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)槿魏晤悾J(rèn)都是已經(jīng)實(shí)現(xiàn)了equals(Object obj)的脂新。 Java中的一切類都是繼承于java.lang.Object挪捕,在Object.java中實(shí)現(xiàn)了equals(Object obj)函數(shù);所以争便,其它所有的類也相當(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 都是用來實(shí)現(xiàn)集合中元素的比較、排序的发绢。當(dāng)我們定義的某個類需要進(jìn)行排序時(shí)硬耍,就要考慮實(shí)現(xiàn)Comparable或Comparator接口。
我們定義一個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類中實(shí)現(xiàn)了Comparable接口朴摊,并重寫了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接口甚纲,并重寫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();
}
}
通過上面的兩種實(shí)現(xiàn)方式:
區(qū)別:
- Comparable接口是在集合內(nèi)部定義的方法實(shí)現(xiàn)的排序口锭。
- Comparator接口是在集合外部實(shí)現(xiàn)的排序。
- 簡單來說介杆,comparable接口是通過類自己完成比較鹃操,而comparator接口是通過外部程序?qū)崿F(xiàn)比較。
若同時(shí)實(shí)現(xiàn)Comparable接口和Comparator接口春哨,排序會聽哪個的呢荆隘?
我們設(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接口,并重寫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í)際上便瑟,對于sort排序方法缆毁,若傳入自定義的comparator接口,則會以傳入的comparator方法來實(shí)現(xiàn)排序到涂,否則脊框,會使用類本身的comparable接口方法。
何時(shí)使用comparable践啄,何時(shí)使用comparator浇雹?
- 若我們在對要排序的類的排序規(guī)則比較固定,也就是不常修改時(shí)屿讽,我們考慮實(shí)現(xiàn)comparable接口昭灵。
- 若我們對要排序的類的排序規(guī)則是經(jīng)常變化的,那么我們考慮實(shí)現(xiàn)comparator接口。