课程咨询 :186 8716 1620      qq:2066486918

昆明Java培训 > 达内新闻 > 不同的场景使用不同的泛型通配符
  • 不同的场景使用不同的泛型通配符

    发布:昆明Java培训      来源:达内新闻      时间:2016-09-30

  • 昆明Java培训机构的老师知道,Java泛型支持通配符(Wildcard),可以单独使用一个“?”表示任意类,也可以使用extends关键字表示某一个类(接口)的子类型,还可以使用super关键字表示某一个类(接口)的父类型,但问题是什么时候该用 extends,什么该用super呢?

    (1)、泛型结构只参与“读”操作则限定上界(extends关键字)

    阅读如下代码,想想看我们的业务逻辑操作是否还能继续:

    public static <E> void read(List<? super E> list) {

    for (Object obj : list) {

    //业务逻辑操作

    }

    }

    从List列表中读取元素的操作(比如一个数字列表中的求和计算),你觉得方法read能继续写下去吗?

    答案是:不能,我们不知道list到底存放的是什么元素,只能推断出E类型是父类,但问题是E类型的父类又是什么呢?无法再推断,只有运行期才知道,那么编码器就无法操作了。当然,你可以把它当做是Object类来处理,需要时 转换成E类型---这完全违背了泛型的初衷。在这种情况下,“读”操作如果期望从List集合中读取数据就需要使用extends关键字了,也就是要界定泛型的上界,代码如下:

    public static <E> void read(List<? extends E> list) {

    for (E e : list) {

    //业务逻辑操作

    }

    }

    此时,已经推断出List集合中取出的元素时E类型的元素。具体是什么类型的元素就要等到运行期才确定了,但它一定是一个确定的类型,比如read(Arrays.asList("A"))调用该方法时,可以推断出List中的元素类型是String,之后就可以对Li st中的元素进行操作了。如加入到另外的List<E>中,或者作为Map<E,V>的键等。

    (2)、泛型结构只参与“写”操作则限定下界(使用super关键字)

    先看如下代码能否编译:

    public static <E> void write(List<? extends Number> list){

    //加入一个元素

    list.add(123);

    }

    编译失败,失败的原因是list中的元素类型不确定,也就是编译器无法推断出泛型类型到底是什么,是Integer类型?是Double?还是Byte?这些都符合extends关键字的定义,由于无法确定实际的泛型类型,所以编译器拒绝了此类操作。

    在此种情况下,只有一个元素时可以add进去的:null值,这是因为null是一个万用类型,它可以是所有类的实例对象,所以可以加入到任何列表中。

    Object是否可以?不可以,因为它不是Number子类,而且即使把List变量修改为List<? extends Object>类型也不能加入,原因很简单,编译器无法推断出泛型类型,加什么元素都是无效的。

    在这种“写”的操作的情况下,使用super关键字限定泛型的下界才是正道,代码如下:

    public static <E> void write(List<? super Number> list){

    //加入元素

    list.add(123);

    list.add(3.14);

    }

    甭管它是Integer的123,还是浮点数3.14,都可以加入到list列表中,因为它们都是Number的类型,这就保证了泛型类的可靠性。

    对于是要限定上界还是限定下界,JDK的Collections.copy方法是一个非常好的例子,它实现了把源列表的所有元素拷贝到目标列表中对应的索引位置上,代码如下:

    1    public static <T> void copy(List<? super T> dest, List<? extends T> src) {

    2        int srcSize = src.size();

    3        if (srcSize > dest.size())

    4            throw new IndexOutOfBoundsException("Source does not fit in dest");

    5

    6        if (srcSize < COPY_THRESHOLD ||

    7            (src instanceof RandomAccess && dest instanceof RandomAccess)) {

    8            for (int i=0; i<srcSize; i++)

    9                dest.set(i, src.get(i));

    10        } else {

    11            ListIterator<? super T> di=dest.listIterator();

    12            ListIterator<? extends T> si=src.listIterator();

    13            for (int i=0; i<srcSize; i++) {

    14                di.next();

    15                di.set(si.next());

    16            }

    17        }

    18    }

    源列表是用来提供数据的,所以src变量需要界定上界,要有extends关键字。目标列表是用来写数据的,所以dest变量需要界定下界,带有super关键字。

    如果一个泛型结构既用作“读”操作又用作“写操作”,那该如何进行限定呢?不限定,使用确定的泛型类型即可,如List<E>.

    了解详情请登陆昆明达内Java培训官网(km.Java.tedu.cn)!

    推荐文章

上一篇:强制声明泛型的实际类型

下一篇:警惕泛型是不能协变和逆变的

最新开班日期  |  更多

Java--零基础全日制班

Java--零基础全日制班

开班日期:11/30

Java--零基础业余班

Java--零基础业余班

开班日期:11/30

Java--周末提升班

Java--周末提升班

开班日期:11/30

Java--零基础周末班

Java--零基础周末班

开班日期:11/30

  • 网址:http://km .java.tedu.cn      地址:昆明市官渡区春城路62号证券大厦附楼6楼
  • 课程培训电话:186 8716 1620      qq:2066486918    全国服务监督电话:400-827-0010
  • 服务邮箱 ts@tedu.cn
  • 2001-2016 达内国际公司(TARENA INTERNATIONAL,INC.) 版权所有 京ICP证08000853号-56