总的来说,协变和逆变 都是 子类的实例赋值给父类的变量。
为啥呢, 你要想把父类的实例赋值给子类的变量,那是要报错的
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