今天自己翻了一下前面學(xué)習(xí)的知識,突然間看到這個話題,回想了一下,感覺自己對Comparable和Comparator的理解印象不是很深了。就打算寫一下這一篇博客,重溫一下好了。之后自己再不明確的時候,也可以來翻一下。
區(qū)別
Comparable & Comparator 都是用來實現(xiàn)集合中的元素比較、排序的。其中Comparable是在集合內(nèi)部定義的方法實現(xiàn)的排序,Comparator是在集合外部絲線的排序。所以,要想實現(xiàn)排序的功能,就需要在集合內(nèi)實現(xiàn)Comparable接口的方法(也就是重寫compareTo()方法)或者在集合外實現(xiàn)Comparator接口的方法(也就是重寫compare()方法)。
Comparable位于包java.lang下,Comparator位于包java.util下。
Comparable是一個類本身就已經(jīng)支持比較所需要實現(xiàn)的接口(如String、Integer自己就可以完成比較大小的操作,因為已經(jīng)實現(xiàn)了Comparable接口)。自定義的類需要實現(xiàn)Comparable并把實例對象加入List集合中后才可以排序。而Comparator,我們可以稱之為比較器。當(dāng)這個類不支持自身比較或者自比較的方法不能滿足我的要求的時候,我們可以寫一個比較器來完成兩個對象之間的大小比較。可以說一個是自己完成比較,另外一個是通過外部的來程序完成比較。
用Comparator是策略模式(Strategy design pattern),就是不改變對象自身,而用一個策略對象(strategy object)來改變他的行為。
那就有一個疑問了,為什么需要存在Comparator呢?我們都用Comparable不就好了嗎?哈哈。這里我們就有一個場景啦。比如對于字符串的排序,String類已經(jīng)實現(xiàn)了Comparable接口,它的compareTo()方法是把字符串按照字典順序進(jìn)行排列。那我們?nèi)绻胍址凑臻L度來排序呢?String類是不允許我們修改它而且是一個final類(最終類)是不能被繼承的,也就是說我們不能去重寫compareTo()方法。那么我們就必須實現(xiàn)Comparator接口,生成一個比較器。這樣的解釋應(yīng)該挺明白了吧。
Comparable示例程序
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class StudentComparable implements Comparable<StudentComparable> {
private String name;
private int age;
public StudentComparable(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
StudentComparable that = (StudentComparable) o;
if (getAge() != that.getAge()) {
return false;
}
return getName() != null ? getName().equals(that.getName()) : that.getName() == null;
}
@Override
public int hashCode() {
int result = getName() != null ? getName().hashCode() : 0;
result = 31 * result + getAge();
return result;
}
@Override
public int compareTo(StudentComparable o) {
if (this.name.compareTo(o.getName()) > 0) {
return 1;
}else if (this.name.compareTo(o.getName()) < 0) {
return -1;
}
return 0;
}
@Override
public String toString() {
return "StudentComparable{" + "name='" + name + '\'' + ", age=" + age + '}';
}
public static void main(String[] args) {
List<StudentComparable> list = new ArrayList<>();
list.add(new StudentComparable("Jack", 16));
list.add(new StudentComparable("Mike", 25));
list.add(new StudentComparable("Summer", 17));
list.add(new StudentComparable("Bob", 19));
Collections.sort(list);
for (StudentComparable stu : list) {
System.out.println(stu);
}
}
}
Comparator示例代碼
import java.util.*;
class A implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
int len1 = s1.length();
int len2 = s2.length();
if (len1 > len2) {
return 1;
}else if (len1 < len2) {
return -1;
}else {
return 0;
}
}
}
public class ComparatorTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("cat");
list.add("fish");
list.add("dog");
list.add("panda");
Collections.sort(list, new A());
System.out.println(list);
}
}
注意
在Comparable接口的實現(xiàn)類里,我們要必須重寫compareTo()方法,看需求是否需要重寫hashCode()方法和equals()方法 (有關(guān)hashCode()和equals()的意義和用法,詳見我的另一篇文章(待定))。
在Comparator接口的實現(xiàn)類里,我們必須重寫compare()方法,看需求是否需要重寫hashCode()方法和equals()方法 。
其實上述的hashCode()方法和equals()方法不重寫也是可以的。