给出一些函数示例,这些函数在Java中的重载和重载情况下能证明协方差和协方差?[关闭]


Answers:


154

协方差:

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。其他语言也支持这种风格的互变。

泛型

对于泛型而言,这也是可能的:

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

现在,您可以访问所有covariantList不带通用参数的方法(因为它必须是“扩展对象”),但是吸气剂可以正常工作(因为返回的对象始终为“对象”类型)

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


79
逆变的第一个示例在Java中不起作用。Sub类中的doSomething()是重载,而不是覆盖。
Craig P. Motlin

15
确实。Java在子类型化中不支持相反参数。与所关注方法返回类型的唯一协方差(如第一个示例中所示)。
the_dark_destructor 2012年

好答案。协方差在我看来是合乎逻辑的。但是,您能在JLS中为我描述一个描述逆差的段落吗?为什么调用Sub.doSomething?
米哈伊尔

2
正如克雷格指出的,事实并非如此。我认为这是覆盖和重载之间的冲突,SUN确实(一如既往)选择了向后兼容选项。因此,在Java中,您无法在覆盖方法时使用相反参数。
硬编码

1
很高兴知道我为什么对我的回答不满意。
硬编码

48

协方差:Iterable和Iterator。定义协变量Iterable或几乎总是有意义的IteratorIterator<? extends T>可以用作Iterator<T>-类型参数出现的唯一位置是方法的返回类型next,因此可以放心地转换为T。但是,如果有S扩展T,也可以分配Iterator<S>给type变量Iterator<? extends T>。例如,如果您要定义一个find方法:

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

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

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

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

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

但不是

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

-4

看一下Liskov替代原理。实际上,如果B类扩展了A类,那么只要需要A,您就应该能够使用B。


6
这不能回答问题,而且会产生误导。设计一种变体系统是完全可能的,该变体系统会破坏语义正确性并因此违反LSP。
马特·惠普尔

事实并非如此contra variantsuper.doSomething("String")无法用代替 sub.doSomething(Object)
zinking

这不是问题
OlivierTerrien
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.