Java 中 与 的区别

        有很长一段时间没弄明白,Java 中 <? super T>  与 <? extends T> 的区别,看过网上不少大神的解释,我的能力有限,好多都看到很迷糊,其中有一篇很浅显易懂,因此记下来,分享一下:java

<? extends T>是指:上界通配符(Upper Bounds Wildcards)spa

<? super T> 是指:下界通配符(Lower Bounds Wildcards)code

 

<? extends T> 子类型限定

1. 概述:限定泛型只能为T类型的子类或者自己对象

2. 例子get

List<? extends Number> list2 = new ArrayList<Integer>();

 List<? extends Number> list2 = new ArrayList<Double>();

List<? extends Number> list2 = new ArrayList<Number>();

3. 操做局限性源码

  • 只能作获取的数据操做,在获取数据时,限定了是Number类的子类的泛型, 因此 获取的数据一定能够是Number类自己获取是其子类,但同时,因为子类有可能不少,不能直接获取到其子类对象.
  • 不能作添加的数据操做,在添加数据时,因为泛型是限定Number类的子类或者自己,没法肯定当前列表里保存的是什么类型的数据。

<? super T> 超类型限定

1. 概述:限定泛型只能为T类型的父类或者自己it

2. 例子io

List<? super Integer> list1 = new ArrayList<Integer>();

List<? super Integer> list1 = new ArrayList<Number>();

List<? super Integer> list1 = new ArrayList<Object>();

3. 操做局限性class

  • 只能作添加数据的操做: 在添加数据的时候,经过限定的Integer 父类或者子类的子类型限定泛型,能够插入Integer对象
  • 不能作获取数据的操做: 在获取数据的时候,因为泛型的父类可能有不少种,读取时,不必定可以肯定操做的数据是属于哪一种类型,除非使用object全部类的基类来获取,因为泛型不肯定性,这样会致使数据丢失.

适用领域

PESC原则泛型

  • “Producer Extends,Consumer Super”。若是参数化类型表示一个生产者,就使用<? extends T>;若是它表示一个消费者,就使用<? super T>
  • 生产者使用extends
    若是你须要一个列表提供T类型的元素(即你想从列表中读取T类型的元素),你须要把这个列表声明成<? extends T>,好比List<? extends Integer>,所以你不能往该列表中添加任何元素。

  • 消费者使用super
    若是须要一个列表使用T类型的元素(即你想把T类型的元素加入到列表中),你须要把这个列表声明成<? super T>,好比List<? super Integer>,所以你不能保证从中读取到的元素的类型。

  • 便是生产者,也是消费者
    若是一个列表即要生产,又要消费,你不能使用泛型通配符声明列表,好比List<Integer>。

简单点来讲就是 使用时, 须要频繁的插入数据时, 就使用超类型限定, 须要获取数据时,就使用子类型限定

  1. 频繁往外读取内容的,适合用上界Extends。
  2. 常常往里插入的,适合用下界Super。

源码例子 Collections.copy()

public static <T> void copy(List<? super T> destination, List<? extends T> source) {
    if (destination.size() < source.size()) {
        throw new IndexOutOfBoundsException("destination.size() < source.size(): " +
                destination.size() + " < " + source.size());
    }
    Iterator<? extends T> srcIt = source.iterator();
    ListIterator<? super T> destIt = destination.listIterator();
    while (srcIt.hasNext()) {
        try {
            destIt.next();
        } catch (NoSuchElementException e) {
            // TODO: AssertionError?
            throw new IndexOutOfBoundsException("Source size " + source.size() +
                    " does not fit into destination");
        }

    // 体现点
    // ** srcIt.next()...
    // ** destIt.set()...
        destIt.set(srcIt.next());
    }
}

原址: http://www.jianshu.com/p/2005318f171f

相关文章
相关标签/搜索