在 Java 集合框架中,排序是高頻操作。Java 提供兩種比較機制:Comparable(內部比較器)與 Comparator(外部比較器)。本文通過實戰代碼對比兩者差異、適用場景、多鍵排序實現,助你做正確選型。
實現 Comparable<T> 接口,重寫 compareTo(T o),定義對象「天然」的排序規則。適用於:
Arrays.sort()、Collections.sort()、TreeSet、TreeMap 等class Student implements Comparable<Student> {
private String name;
private int age;
private float score;
public Student(String name, int age, float score) {
this.name = name; this.age = age; this.score = score;
}
@Override
public int compareTo(Student o) {
// 成績降序
if (this.score > o.score) return -1;
if (this.score < o.score) return 1;
// 成績相同時,年齡升序
if (this.age > o.age) return 1;
if (this.age < o.age) return -1;
return 0;
}
@Override public String toString() {
return name + "\t" + age + "\t" + score;
}
}
public class ComparableDemo {
public static void main(String[] args) {
Student[] students = {
new Student("zhangsan", 20, 90f),
new Student("lisi", 22, 90f),
new Student("wangwu", 20, 99f),
new Student("sunliu", 22, 100f)
};
Arrays.sort(students); // 直接排序
for (Student s : students) System.out.println(s);
}
}
輸出:
sunliu 22 100.0
wangwu 20 99.0
zhangsan 20 90.0
lisi 22 90.0
實現 Comparator<T> 接口,重寫 compare(T o1, T o2)。優勢:
Comparator.comparing())
class Student { // 無 Comparable
private String name; private int age; private float score;
// 構造器、getter、toString 省略
}
class StudentComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
if (o1.getScore() > o2.getScore()) return -1;
if (o1.getScore() < o2.getScore()) return 1;
if (o1.getAge() > o2.getAge()) return 1;
if (o1.getAge() < o2.getAge()) return -1;
return 0;
}
}
public class ComparatorDemo {
public static void main(String[] args) {
Student[] students = { /* 同上 */ };
Arrays.sort(students, new StudentComparator()); // 傳入比較器
for (Student s : students) System.out.println(s);
}
}
| 維度 | Comparable | Comparator |
|---|---|---|
| 接口方法 | int compareTo(T o) (1參) | int compare(T o1, T o2) (2參) |
| 修改原類 | 必須 | 不需要 |
| 排序策略數 | 唯一(自然順序) | 可定義無限多個 |
| 適用場景 | 核心領域模型、固定排序 | 第三方類、多維度排序、臨時需求 |
| Java 8 增強 | 無 | comparing()、thenComparing() 鏈式構建 |
// 靜態導入:import static java.util.Comparator.*;
Comparator<Student> cmp = comparing(Student::getScore).reversed() // 成績降序
.thenComparing(Student::getAge); // 年齡升序
Arrays.sort(students, cmp);
// 或流式排序
List<Student> sorted = students.stream().sorted(cmp).collect(toList());
優點:無需顯式實現類、邏輯清晰可讀、易於組合復用。
Student、Order)實現 Comparable,定義業務主排序Comparator,避免污染領域模型compareTo 時保持與 equals 一致:x.compareTo(y)==0 ⇔ x.equals(y),否則 TreeSet、TreeMap 會出現「邏輯刪除失效」等詭異 Bugnull:Comparator.nullsFirst()/nullsLast() 顯式聲明Integer.compare(a, b) 避免溢出,浮點數用 Float.compare/Double.compareComparable 定義「我是誰」,Comparator 定義「你想怎麼看我」。合理搭配兩者,能構建靈活、可維護的排序體系。現代 Java 開發推薦:核心模型實現 Comparable,業務場景用 Comparator 鏈式 API 組合。