// 無泛型 (Java 4)
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0); // 強轉,運行時才發現類型錯誤
// 有泛型 (Java 5+)
List list = new ArrayList();
list.add("hello");
String s = list.get(0); // 編譯期保證類型安全,無強轉
()); // ❌ Java 7 編譯失敗:無法從 addAll 參數推導
限制: 僅支持賦值語境 的構造器推導,方法調用參數、返回值無法推導。
核心升級:編譯器根據 目標類型 推導泛型參數,目標類型來源包括:
List list = ... void process(List list) List getList() (List) obj void process(Listlist) { ... } // Java 8 process(new ArrayList<>()); // ✅ 推導為 ArrayList process(Arrays.asList("a", "b")); // ✅ 推導為 List
staticList emptyList() { return new ArrayList<>(); } List list = emptyList(); // ✅ 推導 T=String // Java 7 需顯式: Collections. emptyList()
class MyClass{ MyClass(T t) { } // 泛型構造器 } // Java 8 MyClass obj = new MyClass<>("hello"); // ✅ 推導 X=Integer, T=String // Java 7 需: new MyClass ("hello") 仍無法推導 T
Collections.emptyList()void processStringList(Listlist) { ... } // Java 7 processStringList(Collections. emptyList()); // 必須顯式 // Java 8 processStringList(Collections.emptyList()); // ✅ 目標類型 List 推導 T=String
@FunctionalInterface interface Converter{ T convert(F from); } // 目標類型 Converter Converter c = s -> Integer.parseInt(s); // ✅ 推導 F=String, T=Integer
JLS 18 節定義:
<T> 的具體類型邊界| 陷阱 | 現象 | 解決 |
|---|---|---|
| 菱形語法省略導致原始類型 | new HashMap() 而非 new HashMap<>() | 始終保留 <>,編譯器會警告 unchecked conversion |
| 推導失敗回退到 Object | List> list = new ArrayList<>(); 推導為 Object | 顯式指定 new ArrayList<String>() |
| 重載方法推導歧義 | 多個適用重載,編譯器報 ambiguous | 顯式提供類型見證 Class. |
| 匿名內部類無法推導 | new Runnable() {} 無目標類型 | 改用 Lambda 或顯式類型 |
| 版本 | 能力 | 標誌性語法 |
|---|---|---|
| Java 5 | 泛型聲明 | List |
| Java 7 | 構造器賦值推導 | new HashMap<>() (菱形語法) |
| Java 8 | 全語境目標類型推導 | process(new ArrayList<>()), Collections.emptyList(), Lambda |
Java 8 的目標類型推導配合 Lambda、Stream API、方法引用,徹底改變了 Java 代碼風格:類型聲明從「到處寫」變為「關鍵處寫」,編譯器承擔了更多樣板推導工作,這正是現代 Java 表達力提升的核心動力之一。