自java 1.5發(fā)行版本后,java中正式加入了泛型(Generic).它提供了一下的優(yōu)勢:
1. 提供了更加嚴格的編譯時類型檢查. 例如,向聲明為List<String>的列表中添加int值,直接在編譯時就會出錯.
2. 消除了類型的cast. 同前面的列表中,取出來的直接就是String類型的元素.不再需要像之前的List一樣,對取出的元素進行目標類型的cast.
3. 實現了generic algorithm. 這是顯而易見的.
不過,我們接著就會看到,java中的泛型是偽泛型的.這主要是由于編譯器的Type Erasure機制導致的.
* 為了應對這種運行時不可用的類型, 在運行時, 將對象的類型信息分為兩種.
* 一種是類型信息是可用的,成為Reifiable type. 包括所有非泛型的類型.
* 而另一種稱為non-Reifiable type, 它是指類型信息在運行時比編譯時類型更少的類型, 包括經過type erasure之后的類型.
* 另外, 對non-Reifiable type有兩個限制: 不能出現在instanceof表達式中, 或者作為數組中的元素.
由于Type Erasure而引發(fā)的偽泛型特征,導致了很多編程上的問題.
- 首先,讓我們看一個泛型繼承的例子.
class Node<T>{
void setData(T data);
}
class StringNode<String>{
void setData(String data);
}
由于type erasure機制,編譯時會將父類的setData方法的參數類型erase為Object,從而導致StringNode并沒有override setData方法.
為了保證多態(tài)性, 編譯器會生成bridge方法.針對上面的例子,會在StringNode類中生產以下的bridge方法.
void setData(Object data){
this.setData((String)data;
}
-
當一個參數化類型的變量(如List<String>)指向一個非參數化的對象(如List)時.會引發(fā)所謂的Heap Pollution問題,例如可能會將Number實例添加到String的List中. 編譯器會對這種情況發(fā)出unchecked warning. 常見的有以下兩種場景:
- 混用raw type和parameterized type.
- 進行unchecked cast.
泛型的非協(xié)變性(invariant). 引用Java官方文檔的例圖說明
例如,有一個方法:
void printList(List<Object> list);
該方法是無法接收List<String>作為參數的.這是非協(xié)變性帶來的繼承性丟失.