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

相關文章
相關標籤/搜索