【java基礎(五十五)】泛型的約束與侷限(二)

不能構造泛型數組

就想不能實例化一個泛型實例一樣,也不能實例化數組。不過原因有所不同,畢竟數組會填充null值,構造時看上去是安全的。不過,數組本身也有類型,用來監控存儲在虛擬機中的數組。這個類型會被擦除。如:

public static <T extends Comparable> T[] minmax(T[] a) {
	T[] mm = new T[2];
}

類型擦除會讓這個方法永遠構造Comparable[2]數組。

如果數組僅僅作爲一個類的私有實例域,就可以將這個數組聲明爲Object[],並且在獲取元素時進行類型轉換。如:

public class ArrayList<E> {
	private Object[] elements;

	@SuppressWarinings("unchecked")
	public E get(int n) {return (E)elements[n];}
	public void set(int n, E e) {elements[n] = e;}
}

實際的實現沒有這麼清晰:

public class ArrayList<E> {
	private E[] elements;
	...
	public ArrayList() {
		elements = (E[])new Object[10];
	}
}

這裏,強制類型轉換E[]是一個假象,而類型擦除使其無法察覺。

由於minmax方法返回T[]數組,使得這一技術無法施展,如果掩蓋這個類型會有運行時錯誤結果。如:

public static <T extends Comparable> T[] minmax(T... a) {
	Object[] mm = new Object[2];
	...
	return (T[])mm;
}

調用

String[] ss = ArrayAlg.minmax("Tom", "Dick", "Harry");

編譯時不會有任何警告。當Object[]引用賦給Comparable[]變量時,將會發生ClassCastException異常。

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

不能在靜態域或方法中引用變量類型。如:

public class Singleton<T> {
	private static T singleInstance; 	// Error
	private static T getSingleInstance() {	// Error
		if (singleInstance == null)
			construct new instance of T;
		return singleInstance;
	}
}

如果這個程序能夠運行,就可以聲明一個Singleton<Random>共享隨機數生成器,聲明一個Singleton<JFileChooser>共享文件選擇器對話框。但是,這個程序無法工作。類型擦除之後,只剩下Singleton類,它只包含一個singleInstance域。因此,禁止使用帶有類型變量的靜態域和方法。

不能拋出或捕獲泛型類的實例

既不能拋出也不能捕獲泛型類對象。實際上,甚至泛型類擴展Throwable都是不合法的。例如,以下定義就不能正常編譯:

public class Problem<T> extends Exception {	// Error,不能繼承Throwable
	...
} 

catch子句中不能使用類型變量,如,以下方法將不能編譯:

public static <T extends Throwable> void doWork(Class<T> t) {
	try {
		...
	} catch (T e) {	// Error,不能在catch子句中使用類型變量
		...
	}
}

不過,在異常規範中使用類型變量是允許的,以下方法是合法的:

public static <T extends Throwable> void doWork(T t) throws T {
	try {
		...
	} catch (Throwable realCause) {
		....
	}
}

捐贈

若你感覺讀到這篇文章對你有啓發,能引起你的思考。請不要吝嗇你的錢包,你的任何打賞或者捐贈都是對我莫大的鼓勵。

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