为了账号安全,请及时绑定邮箱和手机立即绑定

什么是PECS(制作人扩展消费者超级)?

什么是PECS(制作人扩展消费者超级)?

人到中年有点甜 2019-05-21 15:35:52
什么是PECS(制作人扩展消费者超级)?我在阅读泛型时遇到了PECS(制片extends人和消费者的super简称)。能否给我一个人解释如何使用佩奇之间解决困惑extends和super?
查看完整描述

4 回答

?
白板的微信

TA贡献1883条经验 获得超3个赞

tl; dr: “PECS”来自集合的观点。如果您只是从通用集合中提取项目,那么它就是生产者,您应该使用extends; 如果你只是填充物品,它是一个消费者,你应该使用super。如果同时使用相同的集合,则不应使用extendssuper


假设您有一个方法,它将事物的集合作为参数,但您希望它比仅接受a更灵活Collection<Thing>

案例1:您希望浏览集合并对每个项目执行操作。
然后列表是生产者,所以你应该使用Collection<? extends Thing>

原因是a Collection<? extends Thing>可以保存任何子类型Thing,因此每个元素Thing在执行操作时都会表现为。(您实际上无法向a添加任何内容Collection<? extends Thing>,因为您无法在运行时知道该集合的哪个特定子类型Thing。)

案例2:您想要将东西添加到集合中。
然后列表是消费者,所以你应该使用Collection<? super Thing>

这里的推理是不同的Collection<? extends Thing>,无论实际的参数化类型是什么,Collection<? super Thing>都可以随时保持Thing。在这里你不关心列表中已有的内容,只要它允许Thing添加; 这就是? super Thing保证。


查看完整回答
反对 回复 2019-05-21
?
扬帆大鱼

TA贡献1799条经验 获得超9个赞

计算机科学背后的原理被称为

  • 协方差:? extends MyClass

  • 逆变:? super MyClass

  • 不变性/非方差: MyClass


查看完整回答
反对 回复 2019-05-21
?
天涯尽头无女友

TA贡献1831条经验 获得超9个赞

PECS(“ 生产者extends和消费者super ”的缩写)可以解释为:获取和放置原则


获取和放置原则(来自Java泛型和集合)

它指出,


当您只从结构中获取值时,请使用扩展通配符

仅在将值放入结构时使用超级通配符

当你得到和放置时,不要使用通配符。

让我们通过例子来理解它:

1.用于扩展通配符(获取值即生产者extends)


这是一个方法,它采用一组数字,将每个数字转换为a double,然后对它们求和


public static double sum(Collection<? extends Number> nums) {

   double s = 0.0;

   for (Number num : nums) 

      s += num.doubleValue();

   return s;

}

我们称之为方法:


List<Integer>ints = Arrays.asList(1,2,3);

assert sum(ints) == 6.0;

List<Double>doubles = Arrays.asList(2.78,3.14);

assert sum(doubles) == 5.92;

List<Number>nums = Arrays.<Number>asList(1,2,2.78,3.14);

assert sum(nums) == 8.92;

由于sum()方法的使用extends,所有以下调用都是合法的。如果未使用扩展,前两个调用将不合法。


EXCEPTION:您不能将任何内容 放入使用extends通配符声明的类型中- 除了null属于每个引用类型的值:


List<Integer> ints = new ArrayList<Integer>();

ints.add(1);

ints.add(2);

List<? extends Number> nums = ints;

nums.add(null);  // ok

assert nums.toString().equals("[1, 2, null]");

2.对于超级通配符(放置值即消费者super)


这是一个方法,它接受数字和a的集合int n,并将n从零开始的第一个整数放入集合中:


public static void count(Collection<? super Integer> ints, int n) {

    for (int i = 0; i < n; i++) ints.add(i);

}

我们称之为方法:


List<Integer>ints = new ArrayList<Integer>();

count(ints, 5);

assert ints.toString().equals("[0, 1, 2, 3, 4]");

List<Number>nums = new ArrayList<Number>();

count(nums, 5); nums.add(5.0);

assert nums.toString().equals("[0, 1, 2, 3, 4, 5.0]");

List<Object>objs = new ArrayList<Object>();

count(objs, 5); objs.add("five");

assert objs.toString().equals("[0, 1, 2, 3, 4, five]");

由于count()方法使用super,所有以下调用都是合法的:如果不使用super,则最后两次调用将不合法。


EXCEPTION:你不能从使用super通配符声明的类型中获取任何东西 - 除了type的值Object,它是每个引用类型的超类型:


List<Object> objs = Arrays.<Object>asList(1,"two");

List<? super Integer> ints = objs;

String str = "";

for (Object obj : ints) str += obj.toString();

assert str.equals("1two");

3.当获取和放置时,不要使用通配符


无论何时将值放入并从同一结构中获取值,都不应使用通配符。


public static double sumCount(Collection<Number> nums, int n) {

   count(nums, n);

   return sum(nums);

}


查看完整回答
反对 回复 2019-05-21
  • 4 回答
  • 0 关注
  • 611 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号