pecs原则指导泛型通配符选择:只读用? extends t(生产者),只写用? super t(消费者),读写并存则用具体类型t;jdk中collections.copy等方法已实践该原则。

Java 泛型中用通配符配合 PECS 原则,核心是按数据流向选对类型:只往外拿数据,用 ? extends T;只往里塞数据,用 ? super T;既读又写,就别用通配符,直接用具体类型 T。
什么时候该用 ? extends T(生产者)
当你只从集合中读取元素、不添加新内容时,它就是“生产者”。? extends T 表示容器里装的是 T 或它的任意子类,所以读出来的每个元素都能安全当作 T 用。
- ✅ 允许操作:遍历、
get()、调用T定义的方法(如doubleValue()) - ❌ 禁止操作:
add()、set()(除null外),因为编译器无法确认实际类型是Integer还是Double - ? 示例:
List extends Number>可接收ArrayList<integer></integer>或LinkedList<bigdecimal></bigdecimal>,但不能往里加任何数字
什么时候该用 ? super T(消费者)
当你只往集合中添加元素、不依赖读出的具体类型时,它就是“消费者”。? super T 表示容器能装 T 或它的任意父类,所以任何 T 实例都能安全写入。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- ✅ 允许操作:
add(T)、addAll()(JDK 内部大量使用此模式) - ❌ 禁止操作:把
get(0)直接当T用——返回类型只有Object,需强转才安全 - ? 示例:
List super Integer>可指向ArrayList<number></number>或ArrayList<object></object>,往里加new Integer(42)总是合法
常见误用与规避方式
通配符不是万能适配器,滥用反而引发编译错误或运行隐患。
- 试图在
? extends T集合里add()—— 编译失败,这是类型安全的主动拦截 - 把
? super T的get()结果直接强转为T—— 可能抛ClassCastException,应先检查类型或改用确定泛型 - 在需要读写并存的场景硬套通配符 —— 拆方法(一个只读、一个只写),或直接用
List<t></t> - 对
final类(如String)用? extends String—— 语法合法但无意义,因无子类,等价于? extends String≡String
真实开发中的典型用法
PECS 不是理论空谈,JDK 自身已大量实践。
-
Collections.copy(List super T> dest, List extends T> src):目标列表是消费者(super),源列表是生产者(extends),完美体现组合场景 -
Collection.<t>addAll(Collection super T> c)</t>:确保任意T元素都能加入目标集合 - 工具方法签名如
public static <t> void sum(List extends Number> numbers)</t>:明确只读语义,支持所有数字子类型传入
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










