原始類型(如 List)會繞過泛型檢查,導致運行時 ClassCastException;參數化類型(如 List<String>)在編譯期捕獲類型錯誤,消除強制轉換。
// JDK 7+ 鑽石操作符 <> 讓編譯器推斷類型參數
List<String> list = new ArrayList<>(); // 推薦寫法
List vs List<Object> 關鍵區別List:逃避泛型檢查,可插入任意對象,類型不安全List<Object>:明確聲明持有任意類型,受泛型約束,類型安全泛型信息在編譯後被擦除,List<String> 和 List<Integer> 運行時都是 List。
List<String> strList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();
System.out.println(strList.getClass() == intList.getClass()); // true
// 通過反射繞過編譯檢查(僅作演示,生產禁用)
Method m = intList.getClass().getMethod("add", Object.class);
m.invoke(intList, "string"); // 運行時成功插入字符串!
System.out.println(intList); // [string]
List.class 合法,List<String>.class 非法if (o instanceof Set) 再轉型 Set<?>原則:範圍最小化,優先修復代碼而非抑制警告。
// 差:整個方法抑制
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) { ... }
// 優:僅在必要變量聲明抑制
public <T> T[] toArray(T[] a) {
if (a.length < size) {
@SuppressWarnings("unchecked")
T[] result = (T[]) Arrays.copyOf(elementData, size, a.getClass());
return result;
}
...
}
| 特性 | 數組 | 泛型 |
|---|---|---|
| 類型關係 | 協變:String[] 是 Object[] 子類型 | 不可變:List<String> 不是 List<Object> 子類型 |
| 類型檢查 | 運行時檢查(具體化) | 編譯時檢查,運行時擦除 |
| 錯誤發現 | 運行時 ArrayStoreException | 編譯時錯誤 |
Object[] objArr = new String[1];
objArr[0] = 3; // 編譯通過,運行拋異常
List<Object> objList = new ArrayList<String>(); // 編譯錯誤
objList.add(3); // 編譯直接攔截
public class Stack<E> {
private E[] elements;
private int size = 0;
private static final int DEFAULT_CAPACITY = 16;
@SuppressWarnings("unchecked")
public Stack() {
elements = (E[]) new Object[DEFAULT_CAPACITY]; // 必須抑制警告
}
public void push(E e) {
ensureCapacity();
elements[size++] = e;
}
public E pop() {
if (size == 0) throw new EmptyStackException();
E e = elements[--size];
elements[size] = null; // 消除過期引用
return e;
}
// ...
}
// 聯合兩個集合
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
Set<E> result = new HashSet<>(s1);
result.addAll(s2);
return result;
}
// 類型安全的異構容器模式
public static <K, V> Map<K, V> newHashMap() {
return new HashMap<K, V>();
}
private static UnaryFunction<Object> IDENTITY_FN =
new UnaryFunction<Object>() {
public Object apply(Object arg) { return arg; }
};
@SuppressWarnings("unchecked")
public static <T> UnaryFunction<T> identityFunction() {
return (UnaryFunction<T>) IDENTITY_FN; // 利用擦除共享單例
}
<T extends Comparable<T>> // T 能與自身比較
<T extends Comparable<? super T>> // 更靈活:T 能與父類型比較
List<?>表示未知類型的列表,只能讀取 Object,不能添加元素(除 null)。
Producer Extends, Consumer Super
<? extends T>:生產者(讀取),只能獲取 T 或子類,不能寫入<? super T>:消費者(寫入),可接受 T 或父類,讀取只能作 Objectpublic class Stack<E> {
// pushAll:元素生產者 → extends
public void pushAll(Iterable<? extends E> src) {
for (E e : src) push(e);
}
// popAll:元素消費者 → super
public void popAll(Collection<? super E> dst) {
while (!isEmpty()) dst.add(pop());
}
}
// 使用示例
Stack<Number> numStack = new Stack<>();
Iterable<Integer> ints = Arrays.asList(1,2,3);
Collection<Object> objs = new ArrayList<>();
numStack.pushAll(ints); // Integer extends Number ✓
numStack.popAll(objs); // Object super Number ✓
extends/super 通配符增強靈活性@SuppressWarnings("unchecked") 僅用於無法消除的合理轉換,並縮小範圍List<E> 替代 E[],避免數組與泛型混用