1. 程式人生 > >Java泛型三:萬用字元詳解extends super

Java泛型三:萬用字元詳解extends super

在java泛型中,? 表示萬用字元,代表未知型別,< ? extends Object>表示上邊界限定萬用字元,< ? super Object>表示下邊界限定萬用字元。

萬用字元 與 T 的區別

T:作用於模板上,用於將資料型別進行引數化,不能用於例項化物件。
?:在例項化物件的時候,不確定泛型引數的具體型別時,可以使用萬用字元進行物件定義。

< T > 等同於 < T extends Object>
< ? > 等同於 < ? extends Object>

例一:定義泛型類,將key,value的資料型別進行< K, V >引數化,而不可以使用萬用字元。

public class Container<K, V> {
    private K key;
    private V value;

    public Container(K k, V v) {
        key = k;
        value = v;
    }
}

例二:例項化泛型物件,我們不能夠確定eList儲存的資料型別是Integer還是Long,因此我們使用List<? extends Number>定義變數的型別。

List<? extends Number> eList = null;
eList = new
ArrayList<Integer>(); eList = new ArrayList<Long>();

上界型別萬用字元(? extends)

List<? extends Number> eList = null;
eList = new ArrayList<Integer>();
Number numObject = eList.get(0);  //語句1,正確

//Type mismatch: cannot convert from capture#3-of ? extends Number to Integer
Integer intObject = eList.get(0
); //語句2,錯誤 //The method add(capture#3-of ? extends Number) in the type List<capture#3-of ? extends Number> is not applicable for the arguments (Integer) eList.add(new Integer(1)); //語句3,錯誤

語句1:List<? extends Number>eList存放Number及其子類的物件,語句1取出Number(或者Number子類)物件直接賦值給Number型別的變數是符合java規範的。
語句2:List<? extends Number>eList存放Number及其子類的物件,語句2取出Number(或者Number子類)物件直接賦值給Integer型別(Number子類)的變數是不符合java規範的。
語句3:List<? extends Number>eList不能夠確定例項化物件的具體型別,因此無法add具體物件至列表中,可能的例項化物件如下。

eList = new ArrayList<Integer>();
eList = new ArrayList<Long>();
eList = new ArrayList<Float>();

總結:上界型別萬用字元add方法受限,但可以獲取列表中的各種型別的資料,並賦值給父型別(extends Number)的引用。因此如果你想從一個數據型別裡獲取資料,使用 ? extends 萬用字元。限定萬用字元總是包括自己。

下界型別萬用字元(? super )

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

//Type mismatch: cannot convert from capture#5-of ? super Integer to Number
Number numObj = sList.get(0);  //語句1,錯誤

//Type mismatch: cannot convert from capture#6-of ? super Integer to Integer
Integer intObj = sList.get(0);  //語句2,錯誤

sList.add(new Integer(1));  //語句3,正確

語句1:List<? super Integer> 無法確定sList中存放的物件的具體型別,因此sList.get獲取的值存在不確定性,子類物件的引用無法賦值給兄弟類的引用,父類物件的引用無法賦值給子類的引用,因此語句錯誤。
語句2:同語句1。
語句3:子類物件的引用可以賦值給父類物件的引用,因此語句正確。
總結:下界型別萬用字元get方法受限,但可以往列表中新增各種資料型別的物件。因此如果你想把物件寫入一個數據結構裡,使用 ? super 萬用字元。限定萬用字元總是包括自己。

總結

  • 限定萬用字元總是包括自己
  • 上界型別萬用字元:add方法受限
  • 下界型別萬用字元:get方法受限
  • 如果你想從一個數據型別裡獲取資料,使用 ? extends 萬用字元
  • 如果你想把物件寫入一個數據結構裡,使用 ? super 萬用字元
  • 如果你既想存,又想取,那就別用萬用字元
  • 不能同時宣告泛型萬用字元上界和下界