在Java泛型中如何使用逆变?

在Java泛型中如何使用逆变?,java,generics,contravariance,Java,Generics,Contravariance,在Java中,协方差允许API设计器指定实例可以泛化为特定类型或该类型的任何子类型。例如: List<? extends Shape> shapes = new ArrayList<Circle>(); // where type Circle extends Shape List那么,您的第二个示例将允许您编写: Shape shape = getShapeFromSomewhere(); shapes.add(shape); 但是你不能用第一种形式。我承认,它不

在Java中,协方差允许API设计器指定实例可以泛化为特定类型或该类型的任何子类型。例如:

List<? extends Shape> shapes = new ArrayList<Circle>(); 
// where type Circle extends Shape

List那么,您的第二个示例将允许您编写:

Shape shape = getShapeFromSomewhere();
shapes.add(shape);
但是你不能用第一种形式。我承认,它不如协方差有用

其中一个有用的方面是比较。例如,考虑:

class AreaComparer implements Comparator<Shape>
...

例如,在实现该方法时,需要一个可以包含某种类型T或超类型T的集合。该方法如下所示:

public static <T> void addAll(Collection<? super T> collection, T... objects) {
    // Do something
}

publicstaticvoidaddall(Collection以下是相关摘录:

2.4.获取和放置原则 尽可能插入通配符可能是一种好的做法,但您如何决定 要使用哪种通配符?应该在哪里使用
extends
,应该在哪里使用
super
, 在哪里使用通配符是不合适的

幸运的是,一个简单的原则决定了哪个是合适的

获取和放置原则:使用
在仅获取
值超出结构,请使用
super
仅将值放入 结构,并且不要使用通配符 当你们两个都得到和得到的时候

我们已经在复制方法的签名中看到了这一原则的作用:

public static <T> void copy(List<? super T> dest, List<? extends T> src)

这是否意味着我可以调用Collections.sort(shapes,newcomparator(){…})?对象是@Synesso:Yup,如果你有一个比较器可以比较任意两个对象,可以比较任意两个形状,那么它是安全的。@JonSkeet:不过,我不明白为什么在第二种情况下我们需要显式地
super
。我知道使用
extends
将无助于向列表中添加任何形状,但是
List Shapes=new ArrayList();?
也同样有效,对吗?我认为Oracle的版本对于完全理解
super
在这种情况下的有用性也没有帮助:-(@zencv:要点是,如果您想编写一个方法,将一堆
形状
元素添加到现有列表中,那么您不介意这是
列表
还是
列表
——因此您可以将方法参数设置为
List@Joschua当前位置这不是它的意思-它的意思是“它是某种类型的列表,并且该类型扩展了形状”。因此它可能是(比如)一个
列表
,你不应该在它上面添加一个
圆圈
。一个“包含形状或从其扩展的元素的列表”只是一个
列表
。这也被助记符号“PECS”所知:生产者扩展,消费者超级。(网上有很多解释。)@JoshuaGoldberg是真的,但我不知道在2010年:-)演示代码(无用的IRL):
List l=List.of();
Collections.addAll(l,new Cow(),new Cow());
多亏了相反的方法,我们可以在动物列表中添加奶牛。
public static <T> void addAll(Collection<? super T> collection, T... objects) {
    // Do something
}
public static <T> void copy(List<? super T> dest, List<? extends T> src)
public static double sum(Collection<? extends Number> nums) {
    double s = 0.0;
    for (Number num : nums) s += num.doubleValue();
    return s;
}