(1). 和反射+泛型有關的介面類型
java.lang.reflect.Type:java語言中所有類型的公用父接口
java.lang.reflect.ParameterizedType
java.lang.reflect.GenericArrayType
java.lang.reflect.WildcardType
1. Type直接子接口
ParameterizedType,GenericArrayType,TypeVariable和WildcardType四種類型的介面
ParameterizedType: 表示一種參數化的類型,例如Collection
GenericArrayType: 表示一種元素類型是參數化類型或類型變數的陣列類型
TypeVariable: 是各種類型變數的公共父接口
WildcardType: 代表一種通配符類型表達式,例如?, ? extends Number, ? super Integer【wildcard是一個單字:就是「通配符」】
2. Type直接實作子類別:Class類
3. java.lang.reflect.Type接口
Type所有類型指涉的有:原始型別(raw types)【對應Class】,參數化類型(parameterizedtypes)【對應ParameterizedType】, 數組類型(array types)【對應GenericArrayType】,類型變數(type variables)【對應TypeVariable 】,基本資料型態(primitivetypes)【仍然對應Class】
4. java.lang.reflect.ParameterizedType接口
ParameterizedType介面類型的意義
表示參數化類型。例如:Map這種參數化類型
取得參數化類型<>中的實際類型
原始碼聲明:Type[] getActualTypeArguments();
【注意】無論<>中有幾層<>嵌套,這個方法僅僅脫去最外層的<>之後剩下的內容就作為這個方法的回傳值。
public static E methodIV(
ArrayList> al1,
ArrayList al2,
ArrayList al3,
ArrayListextends Number> al4,
ArrayList al5){}
那麼他的每一參數整體來看都是參數化類型的。
{1}. 對於ArrayList>,透過getActualTypeArguments()傳回之後,脫去最外層的<>之後,剩餘的型別是ArrayList。因此對這個參數的回傳類型是ParameterizedType。
{2}. 對於ArrayList,透過getActualTypeArguments()傳回之後,脫去最外層的<>之後,剩餘的型別是E。因此對這個參數的回傳類型是TypeVariable。
{3}. 對於ArrayList,透過getActualTypeArguments()傳回之後,脫去最外層的<>之後,剩餘的型別是String。因此對這個參數的回傳類型是Class。
{4}. 對於ArrayListextends Number>,透過getActualTypeArguments()傳回之後,脫去最外層的<>之後,剩餘的型別是? ExtendsNumber。因此對這個參數的回傳類型是WildcardType。
{5}. 對於ArrayList,透過getActualTypeArguments()傳回之後,脫去最外層的<>之後,剩餘的型別是E[]。因此對這個參數的回傳類型是GenericArrayType。
所以,可能會獲得各種類型的實際參數,所以為了統一,採用直接父類別數組Type[]進行接收。
4. java.lang.reflect. GenericArrayType接口
GenericArrayType介面類型的意義
表示泛型數組類型。如:void method(ArrayList[] al){…}
【注意】<>不能出現在陣列的初始化中,即new數組之後不能出現<>,否則javac無法通過。但是作為引用變數或方法的某個參數是完全可以的。
取得泛型數組中元素的類型
原始碼聲明:Type getGenericComponentType();
【注意】無論從左向右有幾個[]並列,這個方法僅僅脫去最右邊的[]之後剩下的內容就作為這個方法的返回值。
為什麼回傳值類型是Type?
public static E methodV(String[] p1,E[] p2,ArrayList[] p3,E[][] p4){}{1}. 對於String[],透過getComponentType()傳回之後,脫去最右邊的[]之後,剩餘的型別是String。因此對這個參數的回傳類型是Class
{2}. 對於E[],經由getComponentType()回傳之後,脫去最右邊的[]之後,剩餘的型別是E。因此對這個參數的回傳類型是TypeVariable
{3}. 對於ArrayList[],透過getComponentType()回傳之後,脫去最右邊的[]之後,剩餘的型別是ArrayList。因此對這個參數的回傳類型是ParameterizedType
{4}. 對於E[][],透過getComponentType()回傳之後,脫去最右邊的[]之後,剩餘的型別是E[]。因此對這個參數的回傳類型是GenericArrayType
5. java.lang.reflect. GenericArrayType接口
TypeVariable介面類型的意義
表示類型參數或又叫做類型變數。例如:void method(E e){}中的E就是型別變數
取得類型變數的泛型限定的上邊界的類型
原始碼聲明:Type[] getActualTypeArguments();
【注意】這裡面僅僅是上邊界。原因就是型別變數在定義的時候只能使用extends進行(多)邊界限定。不能使用super,否則編譯無法通過。同時extends給出的都是型別變數的上邊界。
為什麼是回傳類型是數組?因為類型變數可以透過&進行多個上邊界限定,因此上邊界有多個,因此傳回值類型是數組類型[ ]。
例如下面的方法:
public static extends Map& Cloneable&Serializable> E methodVI(E e){…}E的第一個上邊界是Map,是ParameterizedType類型
E的第二個上邊界是Cloneable,是Class類型
因此,為統一,傳回值的陣列的元素類型就是Type
6. java.lang.reflect.WildcardType接口
WildcardType介面類型的意義
表示通配符類型的表達式。
例如void printColl(ArrayListal); 中的? extends Number
【注意】根據上面API的註解提示:現階段通配符表達式僅僅接受一個上邊界或下邊界,這個和定義類型變數時候可以指定多個上邊界是不一樣。但是API說了,為了保持擴充性,這裡回傳值型別寫成了陣列形式。實際上現在回傳的數組的大小就是1
取得通配符表達式物件的泛型限定的上邊界的類型
原始碼宣告:Type[] getUpperBounds();
【注意】上面說了,現階段回傳的Type[ ]中的陣列大小就是1個。寫成Type[ ]是為了語言的升級而進行的擴展。
例如下面的方法:
{1}. public static voidprintColl(ArrayListextends ArrayList> al){}
通配符表達式是:?extendsArrayList,這樣extends後面是?的上邊界,這個上邊界是ParameterizedType型別。
{2}. public static voidprintColl(ArrayListextends E> al){}
通配符表達式是:? extends E,這樣extends後面是?的上邊界,這個上邊界是TypeVariable型
{3}.public static voidprintColl(ArrayListextends E[]> al){}
通配符表達式是:? extends E[],這樣extends後面是?的上邊界,這個上邊界是GenericArrayType型別
{4}.public static voidprintColl(ArrayListextends Number> al){}
通配符表達式是:?extends Number,這樣extends後面是?的上邊界,這個上邊界是Class型別
最終統一成Type作為數組的元素類型。
7. Type及其子介面的來歷
一. 泛型出現之前的類型
沒有泛型的時候,只有所謂的原始型別。此時,所有的原始類型都透過字節碼檔案類別Class類別進行抽象化。 Class類別的一個具體物件就代表一個指定的原始型別。
二. 泛型出現之後的類型
泛型出現之後,擴充了資料型別。從只有原始型別擴充了參數化型別、型別變數型別、泛型限定的的參數化型別(含通配符+通配符限定式)、泛型陣列型別。
三. 與泛型有關的類型不能和原始型別統一到Class的原因
[1]. 【產生泛型擦除的原因】
本來新產生的類型+原始類型都應該統一成各自的字節碼文件類型物件。但是由於泛型不是最初Java中的成分。如果真的加入了泛型,涉及到JVM指令集的修改,這是非常致命的。
[2]. 【Java中如何引入泛型】
為了使用泛型的優勢又不真正引入泛型,Java採用泛型擦除的機制來引入泛型。 Java中的泛型只是給編譯器javac使用的,確保資料的安全性和免去強制型別轉換的麻煩。但是,一旦編譯完成,所有的和泛型有關的類型全部擦除。
[3]. 【Class不能表達與泛型有關的類型】
因此,與泛型有關的參數化類型、類型變數類型、泛型限定的的參數化類型(含通配符+通配符限定表達式)、泛型數組類型這些類型全部被打回原形,在字節碼文件中全部都是泛型被擦除後的原始類型,並不存在和自身類型一致的字節碼文件。所以和泛型相關的新擴充進來的類型不能統一到Class類別。
(4). 與泛型有關的類型在Java中的表示
為了透過反射操作這些類型以迎合實際開發的需要,Java就新增了ParameterizedType,GenericArrayType,TypeVariable 和WildcardType幾種類型來代表不能被歸一到Class類別中的類型但是又和原始類型齊名的類型。
(5). Type的引進:統一與泛型有關的型別與原始型別Class
【引入Type的原因】
為了程式的擴展性,最終引入了Type介面作為Class,ParameterizedType,GenericArrayType,TypeVariable和WildcardType這幾種類型的總的父介面。這樣實作了Type型別參數接受以上五種子類別的實參或傳回值型別就是Type型別的參數。
【Type接口中沒有方法的原因】
從上方看到,Type的出現只是起到了透過多態來達到程式擴展性提高的作用,沒有其他的作用。因此Type介面的源碼中沒有任何方法。