在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.