List<?> 表示「存在某種具體類型 T,使其為 List<T>」,不同於原始類型 List(無類型約束)與 List<Object>(明確接受任意對象)。通配符為泛型類型系統提供了類型區間,且不發生協變(List<Integer> 不是 List<Number> 子類型)。
public void rebox(Box<?> box) {
box.put(box.get()); // 編譯錯誤:capture#xxx of ? 不兼容 Object
}
編譯器為每個通配符生成唯一佔位符(capture),get() 返回 Object,無法匹配 put(capture)。
public void rebox(Box<?> box) { reboxHelper(box); }
private <V> void reboxHelper(Box<V> box) { box.put(box.get()); }
reboxHelper 引入類型參數 V,編譯器將通配符捕獲映射為 Vget() 返回 V,完美匹配 put(V)原則:類型參數若在簽名中僅出現一次,優先用通配符;需復用時引入輔助方法命名捕獲類型。
Box<String> box = new BoxImpl<String>(); // String 寫兩次
public class BoxImpl<T> implements Box<T> {
public static <V> Box<V> make() { return new BoxImpl<V>(); }
}
Box<String> box = BoxImpl.make(); // 僅寫一次,編譯器推斷 V=String
Box<String>,編譯器推導 V=StringBoxImpl.<String>make()編譯器對泛型方法調用推斷最具體滿足約束的類型。如 identity(3) 推斷 Integer 而非 Number。捕獲轉換讓編譯器為捕獲類型生成佔位符名,使其參與推斷。
通配符雖復雜(編譯器報錯晦澀、語言規範最繁瑣),但善用捕獲輔助與泛型工廠兩大模式,配合類型推斷,能大幅降低泛型代碼複雜度,實現 API 簡潔與類型安全並存。