Java的协变(extends)和逆变(super),说白了都是子类的实例赋值给父类的变量

总的来说,协变和逆变   都是  子类的实例赋值给父类的变量。

为啥呢, 你要想把父类的实例赋值给子类的变量,那是要报错的

PECS (Producer Extends,Consumer Super)

当客户端是producer,就意味着客户端生成的数据插入你的集合中,你的参数是父类,客户端的数据是子类,所以用extends

当客户端是consumer,就意味着客户端从你的集合里面取数据,你的参数是子类,客户端的数据是父类,所以用super

如下代码: java.util.Collections的copy方法(JDK1.7) 

src, 顾名思义,就是源数据, copy方法要从src中取数据,所以用extends

desc,就是目标数据,copy方法把数据插到desc中,所以用super。

为啥呢?

假设 T 是copy方法中使用的类型。

src的类型我们就叫  input,  input extends T,所以input就是T的子类,

desc的类型我们就叫output,   output super T, 所以output就是T的父类。

所以 input就是output的子类。

 那么copy中的 di 就是ListIterator<Output>,    si 就是ListIterator<Input>

di.set(si.next());    这句话就是把 input 赋值给output。  说白了,就是把 子类的实例赋值给父类的变量。

协变是从 input到  T,  就是从调用方给你的方法数据。  调用方就是数据的产生者。用extends

逆变是从 T 到 output, 就是你的方法给调用方数据。 调用方就是数据的消费者。用super

重要:要注意T的位置,

<? extends T>      ,                T在extends的右边, T是父类,    ?是子类。  ?才是真实的类型, 接收变量的类型是T

<T extends BaseClass>  ,   T在extends的左边, T是子类。 T是真实的类型,接收变量的类型是  BaseClass

<? super T>   ,                    T在super的右边,  T是子类 ,   ?是父类。  ?才是真实的类型,接收变量的类型是?

<T super BaseClass>   ,       T在super的左边,  T是父类。     T是真实的类型,接收变量的类型是T

原文地址:https://www.cnblogs.com/yfdream/p/7878764.html