1.類型擦除是什么天通?
虛擬機(jī)沒有泛型類型對象莫瞬,所有類都屬于普通類。
通過對泛型類提供一個原始類型(山區(qū)類型參數(shù)后的泛型類型名)搓蚪,擦除類型變量蛤售。
2.類型擦除的方式?
擦除類型變量陕凹,替換為限定類型(無限定類型則替換為Object類)
無限定類型擦除:
public class Pair<T>{
private T first;
private T second;
public Pair(T first ,T second){this.first = first; this.second = second;}
public T getFirst(){return this.first;}
public T getSecond(){return this.second;}
public void setFirst(T first){this.first = first;}
public void setSecond(T second){this.second = second;}
}
類型擦除后變?yōu)?/p>
public class Pair<T>{
private T first;
private T second;
public Pair(T first ,T second){this.first = first; this.second = second;}
public T getFirst(){return this.first;}
public T getSecond(){return this.second;}
public void setFirst(T first){this.first = first;}
public void setSecond(T second){this.second = second}
}
限定類型擦除:
class Pair<T extends Manager> {
private T a;
public <T extends Manager> T getA(){return this.a}
public setA(T value){this.a = value}
}
類型擦除后變?yōu)?/p>
class Manager{
private Manager a;
public Manager getA(){return this.a}
public setA(Manager value){this.a = value}
}
3.約束與局限性
使用java泛型時修安排考慮一下限制悍抑,大多限制都是由類型擦除引起
-
基本類型不能作為泛型的類型參數(shù)
類似 Pair<double>和Pair<int>這種寫法是不成立的鳄炉,原因是類型擦除時后Pair為含有Object的類杜耙,而Object類是不能存儲基本數(shù)據(jù)類型的。
解決方式:使用基本數(shù)據(jù)類型的包裝器拂盯,如Integer佑女、Double等 -
運行時類型檢查只適用于原始類型
由于虛擬機(jī)中的對象總是有一個特定的非泛型類型,因此所有的類型查詢只產(chǎn)生原始類型谈竿。泛型類調(diào)用getClass方法也只是返回原始類型而已团驱。
Pair<String> a = new Pair<>("ahdf","dfgr");
Pair<Integer> b = new Pair<>(1,2);
if (a.getClass() == b.getClass()){
System.out.printf("true");
}
//true
if (a instanceof Pair<String>) ; //Error
Pair<String> p = (Pair<String>) a ; //Error
-
不能創(chuàng)建參數(shù)化類型的數(shù)組
數(shù)組會記住原始數(shù)據(jù)類型并對數(shù)據(jù)類型進(jìn)行校驗,比如Pair[]數(shù)組空凸,可以轉(zhuǎn)換為Object數(shù)組嚎花,但試圖往數(shù)組中存入其他類型的數(shù)據(jù)時,就會拋出Array-StoreException的異常呀洲。
而泛型因為泛型擦除紊选,實際是不會保存原數(shù)據(jù)標(biāo)記,出現(xiàn)給
Pair<String>[] table = new Pair<String>[10]; //Error
數(shù)組賦值時
table[0] = new Pair<Integer>();
由于類型擦除道逗,會導(dǎo)致這種類型檢查機(jī)制失效兵罢。
但有一種情況可以支持泛型類型的數(shù)組,即泛型作為個數(shù)可變的參數(shù)傳入方法時
public static <T> void addAll(T... ts){}
這種情況只會得到一個警告,可以通過@SafeVarargs標(biāo)注方法的方式消除警告 -
不能實例化參數(shù)變量
不能使用像new T()這樣的寫法滓窍。因為類型擦除會將T改為Object卖词,而這種實例化方式只會實例化出一個Object對象。
解決方式:
1)提供構(gòu)造器表達(dá)式
2)通過反射調(diào)用Class.newInstance方法來構(gòu)造泛型對象 - 不能構(gòu)造泛型數(shù)組(吏夯?)
- 不能在靜態(tài)域或方法中引用類型變量
public class Singleton<T>{
private static T singleInstance; //Error
public static T getSingleInstance(){ //Error
....
}
}
與泛型特性有關(guān)此蜈,可參見https://blog.csdn.net/aabbwoshishei/article/details/50187679的示例
- 不能拋出或補(bǔ)貨泛型類的示例(即横?)
4.泛型類型的繼承規(guī)則
泛型學(xué)習(xí)(一)中提到過泛型的繼承規(guī)則,這種繼承規(guī)則限制如此嚴(yán)格的原因與上文提到的不能創(chuàng)建數(shù)組的原因類似裆赵。
Pair<Manager> managers = new Pair<>(ceo,cfo);
Pair<Employee> employees = managers ; //illegal
employee.setFirst(lowlyEmploee);
managers和employees 實際上是引用的同樣的對象令境,但由于泛型的類型擦除,使得managers 也能存放employees 對象顾瞪,這對于managers 來說是不可能成立的舔庶。