這篇文章談一談Java泛型聲明<? extends E>和<? super E>的做用和區別java
<? extends E> 是 Upper Bound(上限) 的通配符,用來限制元素的類型的上限,好比安全
表示集合中的元素類型上限爲Fruit類型,即只能是Fruit或者Fruit的子類,所以對於下面的賦值是合理的app
若是集合中元素類型爲Fruit的父類則會編譯出錯,好比dom
有了上面的基礎,接着來看看 <? extends E>限定的集合的讀寫操做ide
一、寫入ui
由於集合fruits中裝的元素類型爲Fruit或Fruit子類,直覺告訴咱們,往fruits中添加一個Fruit類型對象或其子類對象是可行的spa
結果是編譯都不經過,爲何?由於<? extends Fruit>只是告訴編譯器集合中元素的類型上限,但它具體是什麼類型編譯器是不知道的,fruits能夠指向ArrayList<Fruit>,也能夠指向ArrayList<Apple>、ArrayList<Banana>,也就是說它的類型是不肯定的,既然是不肯定的,爲了類型安全,編譯器只能阻止添加元素了。舉個例子,當你添加一個Apple時,但fruits此時指向ArrayList<Banana>,顯然類型就不兼容了。固然null除外,由於它能夠表示任何類型。.net
二、讀取 code
不管fruits指向什麼,編譯器均可以肯定獲取的元素是Fruit類型,全部讀取集合中的元素是容許的對象
補充:<?>是<? extends Object>的簡寫
<? super E> 是 Lower Bound(下限) 的通配符 ,用來限制元素的類型下限,好比
表示集合中元素類型下限爲Apple類型,即只能是Apple或Apple的父類,所以對於下面的賦值是合理的
若是元素類型爲Apple的子類,則編譯不一樣過
一樣看看<? super E>限定的集合的讀寫操做
一、寫入
由於apples中裝的元素是Apple或Apple的某個父類,咱們沒法肯定是哪一個具體類型,可是能夠肯定的是Apple和Apple的子類是和這個「不肯定的類」兼容的,由於它確定是這個「不肯定類型」的子類,也就是說咱們能夠往集合中添加Apple或者Apple子類的對象,因此對於下面的添加是容許的
它沒法添加Fruit的任何父類對象,舉個例子,當你往apples中添加一個Fruit類型對象時,但此時apples指向ArrayList<Apple>,顯然類型就不兼容了,Fruit不是Apple的子類
二、讀取
編譯器容許從apples中獲取元素的,可是沒法肯定的獲取的元素具體是什麼類型,只能肯定必定是Object類型的子類,所以咱們想得到存儲進去的對應類型的元素就只能進行強制類型轉換了
問題來了,JDK1.5引入泛型的目的是爲了不強制類型轉換的繁瑣操做,那麼使用泛型<? super E>幹嗎呢?這裏就得談到泛型PECS法則了
* Copies all of the elements from one list into another. After the * operation, the index of each copied element in the destination list * will be identical to its index in the source list. The destination * list must be at least as long as the source list. If it is longer, the * remaining elements in the destination list are unaffected. <p> * * This method runs in linear time. * * @param dest The destination list. * @param src The source list. * @throws IndexOutOfBoundsException if the destination list is too small * to contain the entire source List. * @throws UnsupportedOperationException if the destination list's * list-iterator does not support the <tt>set</tt> operation. */ public static <T> void copy(List<? super T> dest, List<? extends T> src) { int srcSize = src.size(); if (srcSize > dest.size()) throw new IndexOutOfBoundsException("Source does not fit in dest"); if (srcSize < COPY_THRESHOLD || (src instanceof RandomAccess && dest instanceof RandomAccess)) { for (int i=0; i<srcSize; i++) dest.set(i, src.get(i)); } else { ListIterator<? super T> di=dest.listIterator(); ListIterator<? extends T> si=src.listIterator(); for (int i=0; i<srcSize; i++) { di.next(); di.set(si.next()); } } }