不能構造泛型數組
就想不能實例化一個泛型實例一樣,也不能實例化數組。不過原因有所不同,畢竟數組會填充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) {
....
}
}
捐贈
若你感覺讀到這篇文章對你有啓發,能引起你的思考。請不要吝嗇你的錢包,你的任何打賞或者捐贈都是對我莫大的鼓勵。