副标题#e#
在定义泛型类型Generic的时候,也可以使用extends通配符来限定T的类型:
public class Generic<T extends Number> { … }
现在,我们只能定义:
Generic<Number> p1 = null;
Generic<Integer> p2 = new Generic<>(1, 2);
Generic<Double> p3 = null;
因为Number、Integer和Double都符合。
非Number类型将无法通过编译:
Generic<String> p1 = null; // compile error!
Generic<Object> p2 = null; // compile error!
因为String、Object都不符合,因为它们不是Number类型或Number的子类。
我们看一个例子:
public class Test {
static class Food {
}
static class Fruit extends Food {
}
static class Apple extends Fruit {
}
static class Orange extends Fruit {
}
public void testExtend() {
List<? extends Fruit> list = new ArrayList<Apple>();
//无法安全添加任何具有实际意义的元素,报错,extends为上界通配符,只能取值,不能放.
//因为Fruit的子类不只有Apple还有Orange,这里不能确定具体的泛型到底是Apple还是Orange,所以放入任何一种类型都会报错
//list.add(new Apple());
//list.add(new Orange());
//可以添加null,因为null可以表示任何类型
list.add(null);
//可以正常获取,用java多态
Food foot = list.get(0);
Apple apple = (Apple) list.get(0);
}
public void testSuper() {
List<? super Fruit> list = new ArrayList<Fruit>();
//super为下界通配符,可以存放元素,但是也只能存放当前类或者子类的实例,以当前的例子来讲,
list.add(new Fruit());
list.add(new Apple());
//无法确定Fruit的父类是否只有Food一个(Object是超级父类)
//因此放入Food的实例编译不通过,只能放自己的实例 或者根据java多态的特性放子类实例
//list.add(new Food());
//List<? super Fruit> list2 = new ArrayList<Apple>();
//Fruit fruit = list.get(0); //不能确定返回类型
}
}
#p#副标题#e#
在testExtend方法中,因为泛型中用的是extends,在向list中存放元素的时候,我们并不能确定List中的元素的具体类型,即可能是Apple也可能是Orange。因此调用add方法时,不论传入new Apple()还是new Orange(),都会出现编译错误。
理解了extends之后,再看super就很容易理解了,即我们不能确定testSuper方法的参数中的泛型是Fruit的哪个父类,因此在调用get方法时只能返回Object类型。结合extends可见,在获取泛型元素时,使用extends获取到的是泛型中的上边界的类型(本例子中为Fruit),范围更小。