您好,欢迎访问一九零五行业门户网

Java泛型之协变、逆变、extends与super选择方法

要了解协变与逆变,首先要引入:
根据 liskov替换原则,如果c是p的子类,则p可以代替c,即 p p = new c();
c继承于p,记做为 c < p
什么是不变如果f是不变,当 c <= p 时,那么 f(c) 和 f(p) 没有任何继承关系
除例如 integer是 number的子类,根据 liskov替换原则
number number = new integer(1); //correct
但是如果这样写就会报错
list<number> list = new arraylist<integer>(1); //error
虽然 number和 integer存在继承关系:integer < number, 但在java里,泛型默认是不变的, 因此也可以看作为 list<number> 和list<integer> 不存在任何继承关系
什么是协变如果f是协变的,当 c <= p 时,那么 f(c) <= f(p)
java 提供了一个extends来将不变转为协变,例如:
list<? extends number> list = new arraylist<integer>(1); //corrent
此时的list<? extends number>可以看作为arraylist<integer>的父类
? extend number可以看作为一个类型范围,表示number的某一个子类
数组默认是协变的
number[] numbers = new integer[3];
什么是逆变如果f是逆变的,当 c <= p 时,那么 f(c) >= f(p)
java 提供了一个super来将不变转为协变,例如:
list<? super number> list = new arraylist<object>(1); //corrent
此时的 list<? super number>可以看作为 arraylist<object>的父类
extends 和 super首先,我们看看collection.add的实现:
public interface list<e> extends collection<e> { boolean add(e e); }
下面代码将会报错?? extends number与integer类型不匹配
list<? extends number> list = new arraylist<integer>(); // correctlist.add(integer.valueof(1)); //error
首先在调用add方法时,泛型e自动变成了<? extends number>
第二行报错,也就是说? extends number不是integer的父类。这里要将 list<? extends number>是arraylist<integer>的父类区分开。
? extends number可以看作为一个类型范围中某一个类型,表示number的某一个子类,但又没明确是哪个子类,可能是float,可能是short,也可能是integer的子类(integer被final修饰,不可能有子类,这里只是一种假设情况),它只确定了它的上界为 number,并没有确定下界(有可能存在? extends number< integer),因此 ? extends number不是integer的父类
将上面代码稍做修改就正确了:
list<? super number> list = new arraylist<object>(); // correctlist.add(integer.valueof(1)); //correct
首先因为逆变,list<? super number>是arraylist<object>的父类,第一行正确。
第二行: ? super number是integer的父类,原因是:? super number表示number的某一个父类,可能是serializable也可能是 object 但不管是哪个,number的父类一定是integer的父类,因此第二行也正确
使用extends还是super呢java.util.collections的copy方法(jdk1.7)给了我们答案:
public static <t> void copy(list<? super t> dest, list<? extends t> src) { int srcsize = src.size(); if (srcsize > dest.size()) throw new indexoutofboundsexception("source does not fit in dest"); if (srcsize < copy_threshold || (src instanceof randomaccess && dest instanceof randomaccess)) { for (int i=0; i<srcsize; i++) dest.set(i, src.get(i)); } else { listiterator<? super t> di=dest.listiterator(); listiterator<? extends t> si=src.listiterator(); for (int i=0; i<srcsize; i++) { di.next(); di.set(si.next()); } }}
要从泛型类取数据时,用extends;
要往泛型类写数据时,用super;
既要取又要写,就不用通配符(即extends与super都不用)
private static <e> e getfirst(list<? extends e> list){ return list.get(0);}private static <e> void setfirst(list<? super e> list, e firstelement){ list.add(firstelement);}public static void main(string[] args) { list<integer> list = new arraylist<integer>(); setfirst(list, 1); number number = getfirst(list);}
以上就是java泛型之协变、逆变、extends与super选择方法的详细内容。
其它类似信息

推荐信息