| 術語 | 範例 | 說明 |
|---|---|---|
| 泛型類型 | ArrayList<E> | 帶類型參數的類/介面宣告 |
| 原始類型 | ArrayList | 擦除類型參數後的類型 |
| 類型參數 | E | 佔位符 |
| 參數化類型 | ArrayList<Integer> | 具體化類型參數 |
| 實際類型參數 | Integer | 傳入的具體類型 |
ArrayList raw = new ArrayList<Integer>(); // 無警告
ArrayList<Integer> generic = new ArrayList(); // 未檢查警告
ArrayList<String> s = new ArrayList<Object>(); // 編譯錯誤
ArrayList<Object> o = new ArrayList<String>(); // 編譯錯誤
// 原因:若允許,可向 ArrayList<String> 放入 Integer 破壞類型安全
ArrayList raw = new ArrayList<Integer>();
ArrayList<String> s2 = raw; // 編譯通過(原始類型繞過檢查),運行時風險
// 上界:? extends Number → 只能讀,不能寫(除 null)
List<? extends Number> nums = new ArrayList<Integer>();
Number n = nums.get(0); // 安全
// nums.add(1); // 編譯錯誤
// 下界:? super Integer → 可寫 Integer 及其子類,讀出只能是 Object
List<? super Integer> ints = new ArrayList<Number>();
ints.add(1); // 安全
Object o = ints.get(0); // 僅能作為 Object 讀取
口訣:PECS —— Producer Extends, Consumer Super。
new ArrayList<Integer>().getClass() == new ArrayList<String>().getClass() 為 true。public static <T> void swap(T[] a, int i, int j) {
T tmp = a[i]; a[i] = a[j]; a[j] = tmp;
}
// 呼叫
swap(new String[]{"a","b"}, 0, 1); // T 推斷為 String
swap(new Integer[]{1,2}, 0, 1); // T 推斷為 Integer
// swap(new int[]{1,2}, 0, 1); // 錯誤:基本類型非引用類型(但自動裝箱後 Integer 可行)
Integer 和 Double → Number)。copy(List<String>, String[]) 會按 List<String> 推斷 T 為 String,導致第二參數類型不匹配報錯。public class GenericDao<T> {
public void add(T entity) { /* ... */ }
public T findById(int id) { return null; }
public void delete(T entity) { /* ... */ }
// 靜態成員不能使用類的類型參數 T
// public static T staticMethod() { } // 編譯錯誤
}
class Box<T> {
T field; // 類的 T
public <U> U method(U u) { return u; } // 方法的 U,與類的 T 無關
}
public class GenericReflection {
public void apply(Map<Integer, String> map) {}
public static void main(String[] args) throws Exception {
Method m = GenericReflection.class.getMethod("apply", Map.class);
Type[] types = m.getGenericParameterTypes();
// types[0] -> Map
ParameterizedType pt = (ParameterizedType) types[0];
System.out.println("原始類型: " + pt.getRawType()); // interface java.util.Map
System.out.println("實際參數0: " + pt.getActualTypeArguments()[0]); // class java.lang.Integer
System.out.println("實際參數1: " + pt.getActualTypeArguments()[1]); // class java.lang.String
}
}
關鍵 API:Method.getGenericParameterTypes()、Field.getGenericType()、ParameterizedType.getActualTypeArguments()。
? extends/? super 實現協變/逆變,遵循 PECS 原則。int → Integer)。