在Java泛型中如何使用逆变?
在Java中,协方差允许API设计器指定实例可以泛化为特定类型或该类型的任何子类型。例如:在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); 但是你不能用第一种形式。我承认,它不
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;
}