PECS(Producer extends and Consumer super):它是从集合的角度出发来选择使用 extends 关键字还是使用 super 关键字。
如果从一个泛型集合中获取元素,那么此时这个集合认为自己是生产者,所以它的泛型类型是生产者类型,应该用 extends。如果你想在泛型集合中添加元素,此时集合认为自己是接收者,所以它的泛型类型是消费者类型,应该用 super 关键字。
假设有个参数为集合的方法,但是你想让这个集合更灵活一点,参数不局限于 Collection<Thing>

情形一:遍历集合中所有元素

这个列表的泛型类型就是生产者,应该使用 Collection<? extends Thing>
理由是一个集合 <? extends Thing> 可以保存Thing的任何子类型,因此当您执行操作时,每个元素都将表现为Thing。 (你实际上无法向 Collection<?extends Thing> 添加任何东西,因为你无法在运行时知道集合中的哪个特定子类型。)

情形二:添加元素到集合

这个列表的泛型类型就是消费者,应该使用 Collection<? super Thing>
Collection<? super Thing> 无论实际的参数化类型是什么,它总能容纳 Thing。 在这里你不关心集合中已有的元素,它允许添加元素。

示例代码

父类:

  1. public class Animal {
  2. class SmallDog extends Dog {
  3. }
  4. class BigDog extends Dog {
  5. }
  6. }

子类:

  1. public class Dog extends Animal {
  2. }

测试类:

  1. public static void producerExtends(List<? extends Animal> animals) {
  2. // 读取animals
  3. Animal a1 = animals.get(0);
  4. // 添加animal
  5. //animals.add(new Animal()); //编译不通过
  6. //animals.add(new Dog()); //编译不通过
  7. }
  8. public static void consumerSuper(List<? super Dog> animals) {
  9. animals.add(new Dog());
  10. //animals.add(new Animal()); // 编译不通过
  11. Object dog = animals.get(0);
  12. }
  13. public static void main(String[] args) {
  14. List<Dog> dogs = new ArrayList<>();
  15. dogs.add(new Dog());
  16. producerExtends(dogs);
  17. consumerSuper(dogs);
  18. }

参考资料

What is PECS
Java泛型PECS原则