List<? extends T>和List<? super T>之間由什麼區別?
<? extends T>表示型別的上界,也就是說,引數化的型別可能是T或者T的子類。例如,下面的寫法都是合法的賦值語句:、
List<? extends Number> list = new ArrayList<Number>(); List<? extends Number> list = new ArrayList<Integer>(); //Integer是Number的子類 List<? extends Number> list = new ArrayList<Float>(); //Float也是Number的子類
<? extends T>被設計為用來讀資料的泛型(只能讀取型別為T的元素),原因如下:
(1)在上面賦值的示例中,對讀資料進行分析
1)不管給list如何賦值,可以保證list裡面存放的一定是Number型別或其子類,因此,可以從list列表裡面讀取Number型別的值。
2)不能從list中讀取Integer,因此list裡面存放的是Float值,同理,也不可以從list裡面讀取Float。
(2)對讀資料進行分析
1)不能向list中寫Number,因為list中有可能存放的是Float。
2)不能向list中寫Integer,因為list中有可能存放的是Float。
3)不能向list中寫Float,因為list中有可能存放的是Integer。
從上面的分析可以發現,只能從List<? extends T>讀取T,因為無法確定它實際指向列表的型別,從而無法確定列表裡面存放的實際的型別,所以,無法向列表裡面新增元素。
<? super T>表示型別下界,也就是說,引數化的型別是此型別的超型別(父型別)。
List<? super Float> list = new ArrayList<Float>(); List<? super Float> list = new ArrayList<Number>(); //Number是Float的父類 List<? super Float> list = new ArrayList<Object>(); //Float也是Number的子類
<? super T>被設計為用來寫資料的泛型(只能寫入T或T的子類型別),不能用來讀,分析如下
(1)讀資料
無法保證list裡面一定存放的是Float型別或者Number型別,因為有可能存放的是Object型別,唯一能確定的是list裡面存放的是Object或其子類,但是無法確定具體子類的型別。
正是由於無法確定list裡面存放資料的型別,因此,無法從list裡面讀取資料。
(2)寫資料
1)可以向list裡面寫入Float型別的資料(不管list裡面實際存放的是Float,Number或者Object,寫入Float都是允許的);同理,也可以向list裡面新增Float子類型別的元素。
2)不可以向list裡面新增Number或Object型別的資料,因為list中可能存放的是Float型別的資料。
下面給出兩個泛型使用的場景
public static <T> void copy(List<? super T> dest,List<? extends T> src){
for (int i = 0; i < src.size(); i++) {
dest.set(i,src.get(i));
}
}