java泛型的理解,和為什麼擦出後,還可以得到
java泛型的理解,和為什麼擦出後,還可以得到
開篇
泛型的使用和例子不說了,太多同類型的文章,自己搜搜,本文主要說
- 泛型的來源和影響
- 泛型擦除
- 泛型擦除了,為什麼反射時還可以得到
泛型的來源和影響
在1.5之前沒有泛型的只有class,所有的類都是class,也就是原始型別,我們統一定義了一個class類進行抽象,class類的一個具體物件就是一個類,後面有了泛型,超出了原始型別的定義,我們給class增加了4個平級的型別,他們是,1)引數化型別,就是用了泛型的類。2)型別變數型別,就是泛型裡面的那個型別變數。3)泛型表示式型別 4)引數化泛型陣列型別。這些都是和原始型別平齊的。
但是jvm只可以處理class原始型別,這個是java一開始就定義好的,如果要改的話,就是要在jvm中增加4中位元組碼檔案,對於jvm改的太大,所以我們不改,在javac編譯階段做相容。這個也就是為什麼我們說java的泛型是偽泛型,因為jvm並不支援泛型
泛型擦除
泛型擦除,就是在編譯階段,把我們寫的泛型轉化為jvm所支援的原始型別,也就是class型別,並且保持語法不變。這個中間過程很複雜。網上專門解釋的文章很多。記住就是jvm不認識我們書寫的泛型,javac要做一層轉化。這個也就是意味著我們在jvm中,也就是在執行中執行的程式碼,沒有泛型的程式碼。
泛型擦除了,為什麼反射時還可以得到
我們在上面說的泛型既然被擦除了,為什麼反射時還可以得到我們書寫的泛型呢,這個我找了很多資料才發現,為了方便反射操作,我們在java中定義了一個頂層介面 type他有
- ParameterizedType: 表示一種引數化的型別,比如Collection
- GenericArrayType: 表示一種元素型別是引數化型別或者型別變數的陣列型別
- TypeVariable: 是各種型別變數的公共父介面
- WildcardType: 代表一種萬用字元型別表示式,比如?, ? extends Number, ? superInteger【wildcard是一個單詞:就是“萬用字元”】
就是我們用class型別表示我們上面說的和原始型別平齊的4種類型,方便我們反射的時候使用,獲得泛型的資料。下面我們來回答上面的問題
最後我看資料發現原來javac在編譯的時候,確實在程式碼上把泛型都轉化為原始型別了,也就是實現了擦除,要不然也執行不了,但是對於類,方法和屬性的泛型(方法體內部除外)。javac編譯的時候專門在位元組碼中分配一個元資料存放 叫做Signature。存放我們泛型資訊,方便反射可以得到
import java.util.List;
import java.util.Map;
public class GenericClass<T> { // 1
private List<T> list; // 2
private Map<String, T> map; // 3
public <U> U genericMethod(Map<T, U> m) { // 4
return null;
}
}
//位元組碼
private java.util.Map map;
Signature: Ljava/util/Map;
Signature: length = 0x2
00 0A
//位元組碼
const #10 = Asciz Ljava/util/Map<Ljava/lang/String;TT;>;;
我下面貼幾個比較好的,對我有幫助的連結
[新增連結描述](http://www.cnblogs.com/mylove7/articles/5811748.html)
[新增連結描述](http://rednaxelafx.iteye.com/blog/586212)