在 Collections.sort() 等工具方法中,常見聲明:
public static <T extends Comparable<? super T>> void sort(List<T> list)
看似複雜,實則解決繼承體系中比較邏輯復用的關鍵問題。
| 聲明 | 含義 | 限制 | 靈活性 |
|---|---|---|---|
<T extends Comparable<T>> | T 必須實現 Comparable<T> | 子類若未顯式實現,無法使用 | 低 |
<T extends Comparable<? super T>> | T 實現 Comparable<T> 或繼承父類的 Comparable<父類> | 支援繼承鏈比較邏輯復用 | 高 |
class Animal implements Comparable<Animal> {
protected int age;
public Animal(int age) { this.age = age; }
@Override public int compareTo(Animal other) { return this.age - other.age; }
}
class Dog extends Animal {
public Dog(int age) { super(age); }
// 未實現 Comparable<Dog>,繼承 Comparable<Animal>
}
public static <T extends Comparable<T>> void sortV1(List<T> list) {
Collections.sort(list);
}
List<Animal> animals = Arrays.asList(new Animal(5), new Animal(3));
List<Dog> dogs = Arrays.asList(new Dog(2), new Dog(4));
sortV1(animals); // ✅ 編譯通過:Animal implements Comparable<Animal>
sortV1(dogs); // ❌ 編譯錯誤:Dog 未實現 Comparable<Dog>
錯誤原因:Dog 繼承自 Animal,擁有 Comparable<Animal>,但 Comparable<Dog> 不存在。Java 不允許類別實現兩個不同參數化的同一介面(Comparable<Animal> 和 Comparable<Dog>)。
public static <T extends Comparable<? super T>> void sortV2(List<T> list) {
Collections.sort(list);
}
sortV2(animals); // ✅ Animal implements Comparable<Animal>,Animal 是 Animal 的 super type
sortV2(dogs); // ✅ Dog 繼承 Comparable<Animal>,Animal 是 Dog 的 super type
通過原因:? super T 表示 T 或 T 的任意父類型。Dog 擁有 Comparable<Animal>,而 Animal 是 Dog 的父類型,滿足 ? super Dog。
Effective Java Item 28 核心指導原則:
extends → List<? extends T>super → List<? super T>Comparable 的 compareTo(T other) 是消費者角色(消費 T 類型參數)? super T:接受 T 或其父類型Comparable<Animal> 可作為 Comparable<? super Dog> 使用public class java.util.Date implements Comparable<java.util.Date> { ... }
public class java.sql.Date extends java.util.Date { ... }
java.sql.Date 繼承 java.util.Date,自動擁有 Comparable<java.util.Date>java.sql.Date 無法再 implements Comparable<java.sql.Date>(介面衝突)List<java.sql.Date> 只能用 <T extends Comparable<? super T>> 版本
// 使用類型參數 T:需在多處引用同一類型
public <T extends Comparable<? super T>> T findMax(T candidate, List<T> list) {
for (T element : list) {
if (element.compareTo(candidate) > 0) return element;
}
return candidate;
}
// 僅用通配符:不需引用類型,僅限制參數
public void sortOnly(List<? extends Comparable<? super ?>> list) {
Collections.sort(list); // 編譯錯誤!sort 需要具體 T
}
// 正確:sort 簽名需要類型參數
public static <T extends Comparable<? super T>> void sort(List<T> list)
// S 是 T 的子類型
public <T, S extends T> T copy(S source) {
return source; // S 可作為 T 返回
}
// 實際應用:Collections.copy
public static <T> void copy(List<? super T> dest, List<? extends T> src)
| 誤區 | 正確理解 |
|---|---|
| 用具體類別替代 T 理解 | 類型參數名稱可為任意標識符,<Dog extends ...> 中 Dog 是類型參數而非類別,會遮蔽同名類別 |
| 以為 ? super T 很少用 | Consumer、Comparator、Comparable、addAll 等大量消費者場景必須用 |
| 以為通配符能完全替代類型參數 | 需要返回值、多參數關聯、方法體內實例化時,必須用類型參數 |
<T extends Comparable<? super T>> 是API 靈活性與類型安全的最佳平衡ComparableComparable 作為消費者使用 super