一句话记住
PECS:Producer Extends, Consumer Super
核心概念:箱子的只读/只写
把泛型容器想象成箱子:
| 通配符 | 记忆口诀 | 箱子特性 | 你能做什么 |
|---|
<? extends T> | extends = 读取 | 里面可能是 T 的任何子类 | 只能拿出来(读),不能放进去 |
<? super T> | super = 写入 | 里面可以装 T 的任何父类 | 只能放进去(写),拿出来只能是 Object |
<? extends T> - 上界通配符
含义:这个箱子装的是 T 或 T 的子类,但具体是什么不知道。
1 2 3 4 5 6 7 8
| List<? extends Number> list = new ArrayList<Integer>();
Number n = list.get(0);
|
为什么不能写?
list 实际可能是 ArrayList<Integer>,你往里面塞个 Double,运行时就会爆炸。编译器直接禁止。
<? super T> - 下界通配符
含义:这个箱子装的是 T 或 T 的父类,你可以安全地放入 T。
1 2 3 4 5 6 7 8 9
| List<? super Number> list = new ArrayList<Object>();
list.add(10); list.add(3.14);
Object obj = list.get(0);
|
为什么不能读成 Number?
list 实际可能是 ArrayList<Object>,里面装个 String 也是合法的,你当成 Number 用就会崩溃。
PECS 实战
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public void printNumbers(List<? extends Number> list) { for (Number n : list) { System.out.println(n); } }
public void fillNumbers(List<? super Number> list) { list.add(100); list.add(3.14); }
public void copy(List<? extends Number> src, List<? super Number> dst) { for (Number n : src) { dst.add(n); } }
|
对比总结
1 2 3 4 5 6 7 8 9 10 11 12 13
| List<Integer> integers = Arrays.asList(1, 2, 3);
List<? extends Number> readOnly = integers; Number n = readOnly.get(0);
List<? super Number> writeOnly = new ArrayList<Object>(); writeOnly.add(100); writeOnly.add(3.14);
Object o = writeOnly.get(0);
|
| 场景 | 选用 |
|---|
| 只读不写 | <? extends T> |
| 只写不读 | <? super T> |
| 又读又写 | 不用通配符,直接用 List<T> |
速查表
1 2 3 4 5
| 读取数据 → extends → Producer 写入数据 → super → Consumer
extends: 只能 get,不能 add(除了 null) super: 只能 add,get 出来是 Object
|