在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。 定义一个协变Iterable或Iterator几乎总是有意义的。 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.