TreeSet 基於紅黑樹實現,元素有序且不重複。它提供兩種排序方式:
Comparable 介面,依 compareTo() 升序排列。Comparator 實例,由其 compare() 決定順序。public interface Comparable<T> {
int compareTo(T o);
}
| 類別 | 比較依據 |
|---|---|
| 數值包裝類 | 對應數值大小 |
| Character | Unicode 值 |
| Boolean | true > false |
| String | 字元 Unicode 逐位比較 |
| Date/Time | 時間先後(較晚者較大) |
Comparable 的物件加入 TreeSet,或加入不同型別物件導致比較失敗。equals() 回傳 true 但 compareTo() 不為 0,違反 Set 唯一性語義,導致重複元素被保留。compareTo() 回傳 0 但 equals() 為 false,TreeSet 視為同一位置但實際不同,操作極其混亂。public class Employee implements Comparable<Employee> {
private int id;
private String name;
@Override
public int compareTo(Employee o) {
return Integer.compare(this.id, o.id); // 唯一標識比較
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Employee)) return false;
Employee other = (Employee) obj;
return this.id == other.id; // 與 compareTo 一致
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
當無法修改元素類別、或需多種排序邏輯時,使用 Comparator:
// 降序排列
TreeSet<Integer> descSet = new TreeSet<>((a, b) -> b - a);
// 多欄位排序:先按年齡降序,再按姓名升序
Comparator<User> multi = Comparator
.comparing(User::getAge).reversed()
.thenComparing(User::getName);
TreeSet<User> customSet = new TreeSet<>(multi);
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return s2.getScore() - s1.getScore(); // 分數降序
}
});
compareTo() 或 compare() 判斷元素大小,決定紅黑樹中的插入位置。compareTo() == 0,而非 equals()。equals()、hashCode()、compareTo() 三者語義一致。Comparable,排序邏輯完全由外部 Comparator 控制。深入理解這些機制,能避免生產環境中詭異的資料不一致與效能問題,是 Java 集合框架進階必修課。