Java中的Variance
默认情况下,Java中的Generics都是Invariant. 例如ArrayList不是ArrayList的子类。如下代码说明了原因:
这是因为,我们对一个Generic Collection的操作,往里面放东西和从里面往外拿东西所需要的类型是不一样的。假如Array<P>是Array的父类,根据里氏替换原则,Array<P>的对象一定可以被Array的对象替换。
假如我们需要往里放东西,我们已知 Array<P>::add(P p), 根据替换原则 Array::add应该能接受P, 而我们已知Array::add能接受C, 所以C >= P.
假如我们要往外取东西, P p = Array<P>::get, 根据替换原则 Array.get()应该能被P接受, 所以C能被P接受, 则 P >= C.
综合上面两条,对于一个Generic来说,假如Array<P>是Array的父类,则P = C. 这就是Invariant.
同时我们可以知道两点结论:
如果P是C的父类,假如这个Generic,我们只需要往外取东西(函数的返回值),那么Class<P> 就是 Class 的父类,这就是covariant. 典型的例子: `Iterator<? extends T>`.
如果P是C的父类,假如这个Generic,我们只需要往里放东西(函数的参数),那么Class 就是 Class<P> 的父类,这就是contravariant. 典型的例子: `Consumer<? super T>`.
参考实例代码体会。在这里, List<? extends Number> 可以接受 List, 这就是covariant. Consumer<? super Double> 可以接受 Consumer, 这就是 contravariant.