在Java中演示协变和逆变?

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

协方差:

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

Sub#getSomething是协变的,因为它返回Super#getSomething的返回types的子类(但是满足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() – 方法。 其他语言也支持这种逆转的风格。

generics

对于generics也是可以的:

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

你现在可以访问所有没有使用generics参数的方法(因为它必须是“extends Object”),但是getters会正常工作(因为返回的对象总是types为“Object”)

对于contravariantList ,情况正好相反:你可以使用generics参数访问所有方法(你知道它必须是“String”的超类,所以你可以总是传递一个),但是没有getters(返回的types可能是任何其他的超types串)

协方差:Iterable和Iterator。 定义一个协变IterableIterator几乎总是有意义的。 Iterator<? extends T> Iterator<? extends T>可以像Iterator<T> – types参数出现的唯一地方是next方法的返回types,所以它可以安全地上传到T 但是如果你有S扩展T ,你也可以把Iterator<S>赋给Iterator<? extends T>types的variablesIterator<? extends T> Iterator<? extends T> 。 例如,如果你正在定义一个查找方法:

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

你将不能用List<Integer>5来调用它,所以最好定义为

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

反差:比较器。 使用Comparator<? super T>几乎总是有意义的Comparator<? super T> Comparator<? super T> ,因为它可以像Comparator<T> 。 types参数只作为compare方法参数types出现,所以T可以安全地传递给它。 例如,如果您有一个DateComparator implements Comparator<java.util.Date> { ... }并且想用该比较器对List<java.sql.Date>进行sorting( 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) 

看看Liskov替代原理 。 实际上,如果B类扩展了A类,那么只要需要A就可以使用B.