我在阅读仿制药的时候遇到了PECS (生产者extends和消费者super的缩写)。
有谁能向我解释一下如何用果胶来解决extends和super之间的混淆?
发布于 2010-04-27 17:37:26
博士:的“果胶”是从集合的角度来看的。如果您只是从一个泛型集合中提取项目,那么它是一个生产者,您应该使用extends;如果您只是在填充项目,那么它就是消费者,您应该使用super。如果两者都使用相同的集合,则不应该使用extends或super。
假设您有一个方法,它的参数是一个事物集合,但是您希望它比只接受一个Collection<Thing>更灵活。
案例1:您想要遍历集合并对每一项进行操作。
然后列表是一个生产者,所以您应该使用Collection<? extends Thing>。
其理由是,Collection<? extends Thing>可以保存Thing的任何子类型,因此在执行操作时,每个元素都将表现为Thing。(实际上不能向Collection<? extends Thing>添加任何内容(null除外),因为您无法在运行时知道集合中包含哪些特定的Thing子类型。
案例2:您希望向集合中添加内容.
然后列表是一个使用者,所以您应该使用Collection<? super Thing>。
这里的理由是,与Collection<? extends Thing>不同的是,无论实际参数化类型是什么,Collection<? super Thing>始终可以持有Thing。在这里,您不关心列表中已经有哪些内容,只要它允许添加一个Thing;这是? super Thing所保证的。
发布于 2013-11-02 06:34:38
发布于 2015-07-26 06:33:49
在处理集合时,在上、下有界通配符之间进行选择的一个常见规则是PECS。信用
生产者extends和消费者super
t (extend)和Put (Super)原理。
- Use an `extends` wildcard when you only get values out of a structure.
- Use a `super` wildcard when you only put values into a structure.
- And don’t use a wildcard when you both get and put.Java中的示例:
class Super {
Number testCoVariance() {
return null;
}
void testContraVariance(Number parameter) {
}
}
class Sub extends Super {
@Override
Integer testCoVariance() {
return null;
} //compiles successfully i.e. return type is don't care(Integer is subtype of Number)
@Override
void testContraVariance(Integer parameter) {
} //doesn't support even though Integer is subtype of Number
}Liskov替换原则(LSP)指出,“程序中的对象应该与其子类型的实例进行替换,而不改变程序的正确性”。
在编程语言的类型系统中,输入规则。
为了说明这种普遍现象,请考虑数组类型。对于类型动物,我们可以使类型Animal[]
Java示例:
Object name= new String("prem"); //works
List<Number> numbers = new ArrayList<Integer>();//gets compile time error
Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;
myNumber[0] = 3.14; //attempt of heap pollution i.e. at runtime gets java.lang.ArrayStoreException: java.lang.Double(we can fool compiler but not run-time)
List<String> list=new ArrayList<>();
list.add("prem");
List<Object> listObject=list; //Type mismatch: cannot convert from List<String> to List<Object> at Compiletime 更多的例子

bounded(i.e.走向某个地方)通配符:有3种不同口味的通配符:
?或? extends Object -无界通配符.它代表着各种类型的家庭。当你们都得到和放置时使用。? extends T ( T后裔的统治)--一个具有上界的通配符.T是继承层次结构中的高级-most类。当您只从结构中获取extends值时,请使用extends通配符。? super T ( T祖先的Reign of T祖先)-具有下限的通配符。T是继承层次结构中的下-most类。当您只将super值放入结构中时,请使用super通配符。注意:通配符?表示0或一次,表示未知类型的。通配符可以用作参数的类型,从未用作泛型方法调用(泛型类实例创建)的类型参数。

import java.util.ArrayList;
import java.util.List;
class Shape { void draw() {}}
class Circle extends Shape {void draw() {}}
class Square extends Shape {void draw() {}}
class Rectangle extends Shape {void draw() {}}
public class Test {
public static void main(String[] args) {
//? extends Shape i.e. can use any sub type of Shape, here Shape is Upper Bound in inheritance hierarchy
List<? extends Shape> intList5 = new ArrayList<Shape>();
List<? extends Shape> intList6 = new ArrayList<Cricle>();
List<? extends Shape> intList7 = new ArrayList<Rectangle>();
List<? extends Shape> intList9 = new ArrayList<Object>();//ERROR.
//? super Shape i.e. can use any super type of Shape, here Shape is Lower Bound in inheritance hierarchy
List<? super Shape> inList5 = new ArrayList<Shape>();
List<? super Shape> inList6 = new ArrayList<Object>();
List<? super Shape> inList7 = new ArrayList<Circle>(); //ERROR.
//-----------------------------------------------------------
Circle circle = new Circle();
Shape shape = circle; // OK. Circle IS-A Shape
List<Circle> circles = new ArrayList<>();
List<Shape> shapes = circles; // ERROR. List<Circle> is not subtype of List<Shape> even when Circle IS-A Shape
List<? extends Circle> circles2 = new ArrayList<>();
List<? extends Shape> shapes2 = circles2; // OK. List<? extends Circle> is subtype of List<? extends Shape>
//-----------------------------------------------------------
Shape shape2 = new Shape();
Circle circle2= (Circle) shape2; // OK. with type casting
List<Shape> shapes3 = new ArrayList<>();
List<Circle> circles3 = shapes3; //ERROR. List<Circle> is not subtype of List<Shape> even Circle is subetype of Shape
List<? super Shape> shapes4 = new ArrayList<>();
List<? super Circle> circles4 = shapes4; //OK.
}
/*
* Example for an upper bound wildcard (Get values i.e Producer `extends`)
*
* */
public void testCoVariance(List<? extends Shape> list) {
list.add(new Object());//ERROR
list.add(new Shape()); //ERROR
list.add(new Circle()); // ERROR
list.add(new Square()); // ERROR
list.add(new Rectangle()); // ERROR
Shape shape= list.get(0);//OK so list act as produces only
/*
* You can't add a Shape,Circle,Square,Rectangle to a List<? extends Shape>
* You can get an object and know that it will be an Shape
*/
}
/*
* Example for a lower bound wildcard (Put values i.e Consumer`super`)
* */
public void testContraVariance(List<? super Shape> list) {
list.add(new Object());//ERROR
list.add(new Shape());//OK
list.add(new Circle());//OK
list.add(new Square());//OK
list.add(new Rectangle());//OK
Shape shape= list.get(0); // ERROR. Type mismatch, so list acts only as consumer
Object object= list.get(0); //OK gets an object, but we don't know what kind of Object it is.
/*
* You can add a Shape,Circle,Square,Rectangle to a List<? super Shape>
* You can't get an Shape(but can get Object) and don't know what kind of Shape it is.
*/
}
}仿制药和示例
协方差与反方差根据类型确定兼容性。在这两种情况下,方差都是有向关系。协方差可以翻译为“在同一方向上不同的”或“有-不同的”,而反方差的意思是“在相反的方向上的不同的”或“相反的-不同的”。协变型和反变型并不相同,但两者之间有一定的相关性。这些名称暗示了相关的方向。
https://stackoverflow.com/a/54576828/1697099
https://stackoverflow.com/a/64888058/1697099
https://stackoverflow.com/questions/2723397
复制相似问题