擦除帶來的問題
擦除主要的正當理由是從非泛化代碼到泛化代碼的轉(zhuǎn)變過程,以及在不破壞現(xiàn)有類庫的情況下,將泛型融入Java中。
1.泛型不能用于顯式地引用運行時類型的操作之中,例如instanceof、new
class Erased<T>{
public void f(T t,String a){
//T t = new T(); //error
//T[] ts = new T[100]; //error
//boolean k = a instanceof T; //error
}
}
我們可以把具體類型的Class傳進來解決部分問題
class Erased<T>{
Class<T> kind;
public Erased(Class<T> kind){
this.kind = kind;
}
public void f(String a) throws Exception{
T t = kind.newInstance(); //這個類需要有默認構(gòu)造器,反射知識
T[] ts = (T[]) Array.newInstance(kind,10);
boolean k = kind.isInstance(a);
}
}
2.基本類型不能作為參數(shù)類型
由于擦除的原因,類型參數(shù)會被擦除到上一邊界,邊界是一個類,不兼容基本類型,所以不能聲明List<int>。
Java1.5后有自動包裝機制,可以用List<Integer>實現(xiàn)基本類型的泛化。但是要注意int[]與Integer[]是轉(zhuǎn)化的,在一些需要傳Integer[]的地方不能傳int[].
3.數(shù)組
可以聲明帶泛型的數(shù)組引用,但是不能直接創(chuàng)建帶泛型的數(shù)組對象
List<String>[] stringLists; //可以聲明帶泛型的數(shù)組引用
List<String>[] stringLists2 = new ArrayList<String>[1];//不能直接創(chuàng)建帶泛型的數(shù)組對象
List<String>[] stringLists3 = new ArrayList[1];
可以通過Array.newInstance(Class<T>,int)來創(chuàng)建T[]
4.重載
class Holder<T,E>{
void f(List<T> list){}
void f(List<E> list){}
}
上面的代碼將會編譯不通過,由于擦除的原因,這兩個方法的類型簽名是一樣的。
5.基類劫持了接口
interface Run<T>{
void with(T t);
}
class Animal implements Run<Integer>{
@Override
public void with(Integer integer) {}
}
public class Dog extends Animal implements Run<String>{}//報錯
子類與父類繼承用一個泛型接口,如果兩個泛型類型不同,將會被父類類型劫持
目錄
學會Java泛型系列(零):簡介及目錄
學會Java泛型系列(一):Java泛型
學會Java泛型系列(二):泛型定義與使用
學會Java泛型系列(三):泛型原理-擦除
學會Java泛型系列(四):擦除帶來的問題以及解決辦法
學會Java泛型系列(五):限定符
學會Java泛型系列(六):總結(jié)
學會Java泛型系列(七):常用案例