如何在Javagenerics中使用逆变?
在Java中,协方差允许API设计者指定实例可以被概括为某种类型或任何该类型的子类型。 例如:
List shapes = new ArrayList(); // where type Circle extends Shape
反方差则是另一种方式。 它允许我们指定实例可以概括为某种类型或超类型。
List shapes = new ArrayList(); // where Shape extends Geometry
Javagenerics的逆变是如何有用的? 你什么时候选择使用它?
那么,你的第二个例子可以让你写:
Shape shape = getShapeFromSomewhere(); shapes.add(shape);
而你不能用第一种forms做到这一点。 它不像协方差那样有用,我会授予你。
可比较有用的一个领域是比较。 例如,考虑:
class AreaComparer implements Comparator ...
您可以使用它来比较任何两个形状…所以如果我们也可以使用它来对List
进行排序,那就太好了。 幸运的是,我们可以通过逆变来做到这一点,这就是为什么Collections.sort
的重载:
public static void sort(List list, Comparator super T> c)
以下是Java Generics和Collections的相关摘录:
2.4。 获取和放置原则
尽可能插入通配符可能是一种好习惯,但是如何确定使用哪个通配符? 你应该在哪里使用extends
,你应该在哪里使用super
,以及在哪里使用通配符是不合适的?
幸运的是,一个简单的原则决定哪个是合适的。
获取和放置原则 :当您只从结构中获取值时使用
extends
通配符,当您仅将值放入结构时使用super
通配符,并且当您同时获取和放置时不使用通配符。
我们已经在复制方法的签名中看到了这个原则:
public static void copy(List super T> dest, List extends T> src)
该方法从源src中获取值,因此使用extends
通配符声明它,并将值放入目标dst,因此使用super
通配符声明它。 每当使用迭代器时,都会从结构中获取值,因此请使用extends
通配符。 这是一个采用数字集合的方法,将每个数字转换为double,并将它们相加:
public static double sum(Collection extends Number> nums) { double s = 0.0; for (Number num : nums) s += num.doubleValue(); return s; }
例如,在实现Collections.addAll()方法时,您需要一个可以包含某个类型T或T的超类型的集合。该方法如下所示:
public static void addAll(Collection super T> collection, T... objects) { // Do something }