J2SE 5.0 引入泛型,解決了集合框架長期存在的「型別不安全」問題。在泛型之前,List、Map 等容器只能存放 Object,取出時需強制轉型,執行期才發現型別錯誤:
// 1.4 風格:不安全
List list = new ArrayList();
list.add("Hello");
list.add(new Integer(5)); // 編譯通過,執行期隱患
String s = (String) list.get(1); // ClassCastException!
泛型讓編譯器在編譯期就攔截此類錯誤,構建型別安全、可重用的程式碼。
在類別名稱後使用尖括號宣告型別參數(Type Parameter),慣用單一大寫字母(T、E、K、V):
public class Example<ONE, TWO, THREE> {
private ONE one;
private TWO two;
private THREE three;
public ONE getOne() { return one; }
public void setOne(ONE one) { this.one = one; }
// ... 其餘 getter/setter 省略
public static void main(String[] args) {
// 實例化時指定具體型別
Example<Double, Integer, String> ex = new Example<Double, Integer, String>();
ex.setOne(1.5); // Double
ex.setTwo(2); // Integer (自動裝箱)
ex.setThree("Three"); // String
}
}
關鍵規則:
Double、Integer、String)。new Example()),預設為 Object(原始型別),失去型別檢查優勢,僅為相容舊代碼。int、double)作為型別參數,必須用對應包裝類別(Integer、Double)。有了泛型類別基礎,建立自訂集合只需將元素型別參數化:
public class GenList<T> {
private T[] elements;
private int size = 0;
@SuppressWarnings("unchecked")
public GenList(int capacity) {
// 泛型陣列建立需轉型,因 Java 不支援 new T[]
elements = (T[]) new Object[capacity];
}
public void add(T element) {
if (size < elements.length) {
elements[size++] = element;
}
}
public T get(int index) {
if (index >= 0 && index < size) return elements[index];
return null;
}
public int size() { return size; }
}
// 泛型介面
public interface GenInterface<T> {
void process(T item);
}
// 多型別參數(以逗號分隔)
public class GenMap<K, V> {
public void put(K key, V value) { /* ... */ }
public V get(K key) { return null; }
}
使用時需對應提供所有型別參數:
GenMap<Integer, String> map = new GenMap<Integer, String>();
map.put(1, "One");
Eclipse 3.1 內建泛型類別建立精靈(File → New → Class → 勾選 Generic Type),自動產生型別參數佔位符,大幅簡化開發流程。
| 限制 | 錯誤範例 | 原因 |
|---|---|---|
| 不可實例化型別參數 | T t = new T(); | 型別擦除,執行期無型別資訊 |
| 不可建立泛型陣列 | T[] arr = new T[10]; | 陣列保留執行期型別,與擦除衝突 |
| 靜態成員不可用型別參數 | static T field; | 靜態屬於類別,非實例 |
| 不可繼承 Throwable | class GenEx<T> extends Exception | 例外處理機制需具體型別 |
?:處理未知型別當方法需接受「任意型別的泛型集合」時,使用無界通配符:
// 錯誤:型別參數不可用於方法參數宣告
// public static void print(GenList<T> list) {}
// 正確:使用通配符
public static void print(GenList<?> list) {
for (Object obj : list) System.out.println(obj);
}
進階用法包括上界通配符 <? extends Number> 與下界通配符 <? super Integer>,分別支援「讀取」與「寫入」語義(PECS 原則)。
泛型是 Java 邁向強型別的關鍵里程碑。掌握型別參數宣告、實例化指定具體型別、通配符應對未知型別 三大核心,即可編寫型別安全、可維護的現代化 Java 程式碼。後續文章將深入探討泛型方法、有界型別參數與實戰模式。