我在阅读泛型时遇到了PECS(Producer extends和Consumer super的缩写)。
有人能向我解释一下如何使用PECS来解决extends和super之间的混淆吗?
我在阅读泛型时遇到了PECS(Producer extends和Consumer super的缩写)。
有人能向我解释一下如何使用PECS来解决extends和super之间的混淆吗?
当前回答
使用现实生活中的示例(有一些简化):
想象一列有货车的货运火车,类似于一个列表。如果货物的尺寸与货车相同或更小,您可以将货物放入货车=<?超级货车尺寸>如果您的仓库有足够的空间(大于货物的大小),您可以从货运车上卸载货物=<?扩展DepotSize>
其他回答
简而言之,要记住PECS的三个简单规则:
使用<?如果需要检索对象集合中的类型T。使用<?如果需要将T类型的对象放入一个集合。如果您需要同时满足这两个条件,那么不要使用通配符。像就这么简单。
请记住:
消费者吃晚餐(超级);生产商扩大了其母公司的工厂
计算机科学背后的原理叫做
协方差:?扩展MyClass,矛盾:?超级MyClass和不变性/非方差:MyClass
下图应解释该概念。图片提供:Andrey Tyukin
public class Test {
public class A {}
public class B extends A {}
public class C extends B {}
public void testCoVariance(List<? extends B> myBlist) {
B b = new B();
C c = new C();
myBlist.add(b); // does not compile
myBlist.add(c); // does not compile
A a = myBlist.get(0);
}
public void testContraVariance(List<? super B> myBlist) {
B b = new B();
C c = new C();
myBlist.add(b);
myBlist.add(c);
A a = myBlist.get(0); // does not compile
}
}
tl;博士:“PECS”是从藏品的角度来看的。如果您只是从泛型集合中提取项,那么它是一个生产者,您应该使用extends;如果你只是在填充物品,那么它是一个消费者,你应该使用super。如果同时使用同一集合,则不应使用extends或super。
假设您有一个方法,它以一个集合作为参数,但您希望它比只接受集合<Thing>更灵活。
案例1:你想通过收集并处理每个项目。那么列表是一个生产者,因此您应该使用集合<?扩展Thing>。
理由是集合<?extendsThing>可以保存Thing的任何子类型,因此当您执行操作时,每个元素都将表现为Thing。(实际上不能向集合中添加任何内容(null除外)<?扩展Thing>,因为您无法在运行时知道集合持有Thing的哪个特定子类型。)
案例2:您想要向集合中添加内容。那么列表是消费者,因此您应该使用集合<?超级事物>。
这里的理由是,不同于集合<?扩展Thing>,Collection<?super Thing>可以始终保存Thing,无论实际参数化类型是什么。在这里,只要它允许添加Thing,您就不在乎列表中已经存在什么;这是什么?super Thing保证。