泛型的擦除是擦除到它的边界处,因此无边界泛型参数调用方法只是那些可以用Object调用的方法。但是如果将这个参数限制为某个类型子集,那么你就可用这些类型子集来调用方法。为了执行这种限制,java泛型重用了extends关键字,用于表示泛型上界。
下来看一段代码:
public class GenericsAndCovariance {
public static void main(String[] args) {
List<? extends Fruit> frist = new ArrayList<Apple>();
//会提示编译异常,不可添加任何的Object类型
//frist.add(new Fruit());
//frist.add(new Apple());
//frist.add(new Object());
//frist.add(new Orange());
frist.add(null);
Fruit fruit2 = frist.get(0);
}
}
class Fruit{}
class Apple extends Fruit{}
class Orange extends Fruit{}
List<? extends Fruit> frist代码代表我们从集合中获取的实例可以使用Fruit里面的方法,但是为什么无法往集合里面添加Fruit的子类讷!
因为当你可以往List<? extends Fruit>中添加Fruit的子类,你将会可以添加苹果也可以添加橘子和香蕉。取得话却是安全的,因为无论你取得是何种水果它将都是Fruit类型。
泛型下界 List<? super Apple> 代表apple的所有父类,当我们往里面存入数据的时候,不可存入apple的父类,因为apple或许不止一个父类,它无法辨识我们存入的是哪个父类(但是由于泛型是父类我们可以往集合存入apple和apple的所有子类)。一样的道理,我们调用get方法,可以将数据转为Apple和Apple的父类。
public class GenericsAndCovariance {
public <T> List<? super Apple> wrt(List<? super Apple> list, T item){
//list.add(new Orange());
//list.add(new Fruit());
list.add(new Apple());
return list;
}
public static void main(String[] args) {
List<Fruit> fruits = new ArrayList<Fruit>();
GenericsAndCovariance g = new GenericsAndCovariance();
List<Object> t = (List<Object>) g.wrt(fruits,new Apple());
List<Fruit> t1 = (List<Fruit>)g.wrt(fruits,new Apple());
List<Apple> t2 = (List<Apple>) g.wrt(fruits,new Apple());
//error
//List<Iapple> t3 = (List<Iapple>)g.wrt(fruits,new Apple());
//List<Orange> t2 = (List<Orange>) g.wrt(fruits,new Apple());
}
}
//TODO
class Fruit{}
class Apple extends Fruit{}
class Orange extends Fruit{}
class Iapple extends Apple{}