固原站长网 语言 extends与super通配符的差异

extends与super通配符的差异

副标题#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),范围更小。

上一篇
下一篇
返回顶部