談談Java類型中ParameterizedType,GenericArrayType,TypeVariabl,WildcardType_java

來源:互聯網
上載者:User

(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】,基礎資料型別 (Elementary Data Type)(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介面的源碼中沒有任何方法。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.