java核心之泛型(三)約束

——每天的寥寥幾筆,堅持下去,將會是一份沉甸甸的積累。


從前一篇文章我們可以看出擦除機制的強大,由於擦除,使得新的語法糖——泛型被成功的加入到java語法中,同時又兼容了java虛擬機原有的處理機制。

不過,擦除的加入也帶來了不少的約束與限制。

1.不能用基本類型實例化類型參數。

比如說Pair<double>是不被允許的,因爲類型擦除過後,Pair含有Object類型的域,而Object不能存儲基本數據類型double。


2.運行時類型查詢只適用於原始類型。

因爲泛型類型會被擦除,最後不是我們想要的結果。比如

if(a isinstanceof Pair<String>)//ERROR
由於擦除,結果只會變成判斷是否是Pair的實例,而不是我們原來想要的判斷是否是Pair<String>的實例

3.不能創建參數化類型的數組

Pair<String> [] table = new Pair<String>[10];//ERROR
擦除過後,table的類型爲Pair[],然後
Object[] array = table;
array[0] = "hello";//ERROR-component type is Pair,throw arrayStoreException
array[0] = new Pair<Employee>();//pass the array store check but still result in a type error
如果需要收集參數化類型對象,直接使用ArrayList:ArrayList<Pair<String>>最安全且有效


4.Varargs警告

從3可以看出java不支持泛型類型的數組,然後對應一個類似的——可變參的方法,如addAll(T...ts),往裏面傳泛型類型的參數實例就會垂涎Varargs警告。


5.不能實例化泛型類型

new T(...),new T[...],T.class這些的表達式都不能使用,因爲T會被擦除爲Object
那樣的話結果會始終new出來Object類型的實例,這不是我們想要的。必要時需要用反射來實現

public static <T> Pair<T> makePair(Class<T> c1){
    return new Pair(c1.newInstance(), c1.newInstance());
}
那麼既然new T()不被允許,我們又該怎麼new一個對象出來呢?答案是用Object類型。

看ArrayList的實現

public class ArrayList<E>{
	Object[] element;
	public E get(int n){
		return (E)element[n];
	}
	public void set(int n,E e){
		element[n] = e;
	}
}

這裏需要注意的是,如果返回的不是E類型,而是E[]類型,那麼就出問題,像下面

public static <T> T[] minmax(T...a){
	Object[] mm = new Object[2];
	return (T[])mm;//編譯通過,運行時類型轉換異常
}

上面這種情況還是得需要反射來解決
public static <T> T[] minmax(T...a){
	T[] mm == (T[])Array.newInstance(a.getClass().getComponentType(),2);
	return mm;//編譯通過,運行時類型轉換異常
}


6.泛型類的靜態上下文中類型變量無效

public class A<T>{
	private static T a;//error
	public static T get(){}//error,因爲擦除,而且類A沒有被實例化
}

7.類型擦除後的衝突

publicclass Pair<T>{
	public boolean equals(T value){}//由於擦除,變成equals(Object),這會和從Object父類繼承過來的equals(Object)同名衝突
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章