泛型硬核指南:类型擦除、桥方法、通配符捕获、F 有界与工程 API 设计
大约 4 分钟
泛型硬核指南:类型擦除、桥方法、通配符捕获、F 有界与工程 API 设计
新手先看 · 一屏速览
- 泛型运行期被擦除为上界(默认 Object);多态保持靠桥方法(bridge method)
- PECS:Producer Extends / Consumer Super;读多用 extends,写多用 super
- 泛型数组禁止创建;可变参数 + 泛型需注意堆污染,必要时 @SafeVarargs
1. 类型擦除与桥方法
- 泛型仅在编译期起作用;运行期类型擦除到上界(未指定则为 Object)
- 为保持覆写签名一致,编译器可能生成桥方法(bridge),在字节码层适配擦除后的签名
class Base<T> { T get(){ return null; } }
class Sub extends Base<String> { @Override String get(){ return ""; } }反编译可见:Sub 同时存在 String get() 与 Object get()(bridge)以适配多态调用
2. 通配符与边界
- 上界:
? extends T→ 可读不可写(写入受限为 null),适合“生产者” - 下界:
? super T→ 可写入 T 及其子类,读取为 Object,适合“消费者”
static <T> void copy(List<? extends T> src, List<? super T> dst){ for (T t: src) dst.add(t); }3. 通配符捕获(capture)技巧
当编译器无法从 ? 推断具体类型时,引入私有泛型方法辅助“捕获”:
static void swap(List<?> list, int i, int j){ swapHelper(list, i, j); }
private static <T> void swapHelper(List<T> list, int i, int j){
T tmp = list.get(i); list.set(i, list.get(j)); list.set(j, tmp);
}4. 泛型方法与类型推断
static <T> T first(List<T> list){ return list.get(0); }
var s = first(List.of("a","b"));注意:方法引用与菱形操作符可辅助推断,但复杂上下文需显式参数化
5. F 有界(自绑定)与协变接口
interface Self<T extends Self<T>>{ T merge(T other); }
final class Money implements Self<Money>{ public Money merge(Money o){ /*...*/ return this; } }自绑定约束 API 返回具体子类型(流式 API 常见),避免返回过泛的父类型
6. 创建与数组限制、可变参数
最近建一些几十个工作内推群,各大城市都有,群里目前已经收集了很多内推岗位,大厂、中厂、小厂、外包都有。 欢迎HR、开发、测试、运维和产品加入。

扫描下方微信,备注:网站+所在城市,即可拉你进工作内推群。

- 不能创建泛型数组:
new T[10]、new List<String>[10]均非法 - 可用
List<T>或@SuppressWarnings("unchecked")+ 受控转换(非常谨慎)
@SafeVarargs
static <T> List<T> of(T... items){ return List.of(items); }@SafeVarargs 仅用于保证实现不会导致堆污染(如仅只读遍历)
7. 堆污染、原始类型与桥接开销
- 堆污染:泛型通过擦除绕过编译器检查后在运行期破坏类型安全(通常由不安全转换/可变参数引入)
- 避免使用原始类型(raw type)如
List;使用List<?>或具名List<T> - 桥方法/装箱可能带来微小开销;热路径上可考虑方法内联与专用实现
8. API 设计实践(含比较器与集合)
- 输入为生产者 →
? extends T;输出/落地为消费者 →? super T - Comparator 与集合:排序/合并接口应允许
? super T,例如Comparator<? super T> - 返回只读视图时,使用
List<? extends T>搭配文档说明不修改契约
9. 基准与工程观察
- 对同一逻辑给出泛型与基本类型专用版本,对比调用与内联的差异
- 验证
Comparator<T>vsComparator<? super T>在复杂层级下的可用性与可读性
10. 实战清单与反模式
- 清单:接口边界使用通配符表达“输入/输出”意图;自绑定提升可用性;必要时 @SafeVarargs
- 反模式:滥用原始类型;不必要的
@SuppressWarnings;错误使用上下界导致 API 僵硬
11. 练习
- 实现一个通用
merge:合并两个List<? extends T>到List<? super T> - 设计一组只读/只写视图的泛型容器,验证编译期约束
