無泛型時,集合只能存 Object,取出需強轉,編譯期無法發現類型錯誤,運行期拋 ClassCastException:
List list = new ArrayList();
list.add("hello");
list.add(100); // 編譯通過
String s = (String) list.get(1); // 運行拋 ClassCastException
參數化類型。將類型由具體類型參數化(如方法形參),使用時傳入具體類型實參:
List<String> list = new ArrayList<>();
list.add("hello");
// list.add(100); // 編譯報錯
String s = list.get(0); // 無需強轉
源碼層面:interface List<E> { E get(int index); },E 為類型形參,實例化時替換為實參。
// 泛型類
class Box<T> {
private T data;
public Box(T data) { this.data = data; }
public T getData() { return data; }
}
// 泛型方法(非泛型類中也可定義)
public static <T> void print(T t) { System.out.println(t); }
Box<String> b1 = new Box<>("a");
Box<Integer> b2 = new Box<>(1);
System.out.println(b1.getClass() == b2.getClass()); // true,都是 Box.class
編譯器擦除泛型信息,運行期只有原始類型。因此無法創建泛型數組:new T[10] 非法。
Box<?>表示任意 Box<X> 的父類,可讀不可寫(除 null):
void printBox(Box<?> box) { System.out.println(box.getData()); }
<? extends Number>只能傳入 Number 及其子類(Integer, Double...),只能讀,不能寫(因不確定具體子類型):
void process(Box<? extends Number> box) {
Number n = box.getData(); // OK
// box.setData(1); // 編譯錯誤
}
<? super Integer>只能傳入 Integer 及其父類(Number, Object),可寫,讀出只能是 Object:
void addInt(Box<? super Integer> box) {
box.setData(10); // OK
Object o = box.getData(); // 只能作為 Object 讀
}
Producer Extends, Consumer Super
作為生產者(只讀)用extends;作為消費者(只寫)用super。
List<String> list = new ArrayList<>();void copy(List<? extends T> src, List<? super T> dest)static 字段引用類型參數(會被所有實例共享)。List<T> 或 T[] toArray(T[] a)。?。