在Java中展示协方差和逆变?

时间:2010-03-23 15:14:01

标签: java covariance contravariance

请在Java中展示协方差和逆变的一个很好的例子。

3 个答案:

答案 0 :(得分:141)

<强>协方差:

class Super {
  Object getSomething(){}
}
class Sub extends Super {
  String getSomething() {}
}

Sub#getSomething是协变的,因为它返回Super#getSomething的返回类型的子类(但是满足了Super.getSomething()的合约)

<强>逆变

class Super{
  void doSomething(String parameter)
}
class Sub extends Super{
  void doSomething(Object parameter)
}

Sub#doSomething是逆变的,因为它需要Super#doSomething参数的超类参数(但是,再次填写Super#doSomething的合约)

注意:此示例在Java中不起作用。 Java编译器会重载并且不会覆盖doSomething() - Method。其他语言确实支持这种逆转方式。

<强>泛型

Generics也可以这样做:

List<String> aList...
List<? extends Object> covariantList = aList;
List<? super String> contravariantList = aList;

您现在可以访问不带泛型参数的covariantList的所有方法(因为必须是“extends Object”),但getter将正常工作(如返回的对象将始终为“Object”类型

contravariantList的情况恰恰相反:您可以使用泛型参数访问所有方法(您知道它必须是“String”的超类,因此您始终可以传递一个),但是没有getter(返回的类型)可以是任何其他超类型的字符串)

答案 1 :(得分:45)

协方差:Iterable和Iterator。定义共变IterableIterator几乎总是有意义的。 Iterator<? extends T>可以像Iterator<T>一样使用 - 类型参数出现的唯一位置是next方法的返回类型,因此可以安全地向上转换为T }。但是,如果S扩展T,您还可以将Iterator<S>分配给Iterator<? extends T>类型的变量。例如,如果要定义find方法:

boolean find(Iterable<Object> where, Object what)

您将无法使用List<Integer>5进行调用,因此最好定义为

boolean find(Iterable<?> where, Object what)

Contra-variance:Comparator。使用Comparator<? super T>几乎总是有意义的,因为它可以像Comparator<T>一样使用。 type参数仅作为compare方法参数类型出现,因此T可以安全地传递给它。例如,如果您有DateComparator implements Comparator<java.util.Date> { ... }并且想要使用该比较器对List<java.sql.Date>进行排序(java.sql.Datejava.util.Date的子类),则可以执行以下操作:< / p>

<T> void sort(List<T> what, Comparator<? super T> how)

但不是

<T> void sort(List<T> what, Comparator<T> how)

答案 2 :(得分:-2)

查看Liskov substitution principle。实际上,如果B类扩展了A类,那么只要需要A就可以使用B.