初學者在學習 Java 集合框架時,常對泛型聲明中的 T 和通配符 ? 感到困惑,特別是在 Comparable<T> 等接口定義中。
T(Type Parameter)是類型參數,在定義泛型類/接口/方法時作為具體類型的佔位符:
// 定義階段:T 代表未來將傳入的具體類型
public interface Comparable {
int compareTo(T o); // 參數類型與實現類一致
}
// 使用階段:指定具體類型
public class Student implements Comparable { // T 被替換為 Student
public int compareTo(Student o) { ... }
}
關鍵特性:
<T>List)T 被替換為 Object 或邊界類型? 表示未知類型,主要用於參數聲明而非定義,提供多態靈活性:
| 語法 | 名稱 | 含義 | 適用場景 |
|---|---|---|---|
? | 無界通配符 | 任意類型,等價 ? extends Object | 只需 Object 方法(如 List>.size()) |
? extends T | 上界通配符 | T 或其子類(協變) | 只讀場景,如 List extends Number> |
? super T | 下界通配符 | T 或其父類(逆變) | 只寫場景,如 List super Integer> |
Joshua Bloch 在《Effective Java》提出的核心指導原則:
// 生產者:從集合讀取元素 → 用 extends
public void printNumbers(List extends Number> list) {
for (Number n : list) System.out.println(n); // 安全讀取
// list.add(1); // 編譯錯誤!不能寫入(除 null)
}
// 消費者:向集合寫入元素 → 用 super
public void addIntegers(List super Integer> list) {
list.add(1); // 安全寫入
list.add(2);
// Number n = list.get(0); // 編譯錯誤!只能作為 Object 讀取
}
在 Comparable<T> 中,T 確保比較雙方類型一致:
// 正確:同類比較
List students = ...;
students.sort(Student::compareTo); // T = Student
// 錯誤嘗試:跨類比較(編譯不通過)
// students.sort((a, b) -> a.compareTo((Teacher)b));
若需比較不同但相關類型,可用通配符:
// 通用比較器接受 Number 及其子類
Comparator super Number> cmp = (a, b) -> a.doubleValue() - b.doubleValue();
List<T> 需方法聲明 <T>,否則用 ?? x,只能用於引用類型List 和 List 都是 Listextends 或 supertype NumList = List extends Number>;掌握 T 與 ? 的區別,是寫出類型安全、可復用 Java 代碼的關鍵。建議多閱讀集合框架源碼(如 Collections.sort、Stream API),體會泛型在實際庫設計中的精妙應用。