談?wù)凧ava類型中ParameterizedType,GenericArrayType,TypeVariabl,WildcardType
(1). 和反射+泛型有關(guān)的接口類型
java.lang.reflect.Type:java語言中所有類型的公共父接口
java.lang.reflect.ParameterizedType
java.lang.reflect.GenericArrayType
java.lang.reflect.WildcardType
1. Type直接子接口
ParameterizedType,GenericArrayType,TypeVariable和WildcardType四種類型的接口
ParameterizedType: 表示一種參數(shù)化的類型,比如Collection
GenericArrayType: 表示一種元素類型是參數(shù)化類型或者類型變量的數(shù)組類型
TypeVariable: 是各種類型變量的公共父接口
WildcardType: 代表一種通配符類型表達(dá)式,比如?, ? extends Number, ? super Integer【wildcard是一個(gè)單詞:就是“通配符”】
2. Type直接實(shí)現(xiàn)子類 :Class類
3. java.lang.reflect.Type接口
Type所有類型指代的有:原始類型 (raw types)【對(duì)應(yīng)Class】,參數(shù)化類型 (parameterizedtypes)【對(duì)應(yīng)ParameterizedType】, 數(shù)組類型 (array types)【對(duì)應(yīng)GenericArrayType】,類型變量 (type variables)【對(duì)應(yīng)TypeVariable】,基本數(shù)據(jù)類型(primitivetypes)【仍然對(duì)應(yīng)Class】
4. java.lang.reflect.ParameterizedType接口
ParameterizedType接口類型的含義
表示參數(shù)化類型。比如:Map這種參數(shù)化類型
獲取參數(shù)化類型<>中的實(shí)際類型
源碼聲明:Type[] getActualTypeArguments();
【注意】無論<>中有幾層<>嵌套,這個(gè)方法僅僅脫去最外層的<>之后剩下的內(nèi)容就作為這個(gè)方法的返回值。
public static E methodIV(
ArrayList> al1,
ArrayList al2,
ArrayList al3,
ArrayListextends Number> al4,
ArrayList al5){}
那么他的每一參數(shù)總體上看都是參數(shù)化類型的。
{1}. 對(duì)于ArrayList>,通過getActualTypeArguments()返回之后,脫去最外層的<>之后,剩余的類型是ArrayList。因此對(duì)這個(gè)參數(shù)的返回類型是ParameterizedType。
{2}. 對(duì)于ArrayList,通過getActualTypeArguments()返回之后,脫去最外層的<>之后,剩余的類型是E。因此對(duì)這個(gè)參數(shù)的返回類型是TypeVariable。
{3}. 對(duì)于ArrayList,通過getActualTypeArguments()返回之后,脫去最外層的<>之后,剩余的類型是String。因此對(duì)這個(gè)參數(shù)的返回類型是Class。
{4}. 對(duì)于ArrayListextends Number>,通過getActualTypeArguments()返回之后,脫去最外層的<>之后,剩余的類型是? ExtendsNumber。因此對(duì)這個(gè)參數(shù)的返回類型是WildcardType。
{5}. 對(duì)于ArrayList,通過getActualTypeArguments()返回之后,脫去最外層的<>之后,剩余的類型是E[]。因此對(duì)這個(gè)參數(shù)的返回類型是GenericArrayType。
所以,可能獲得各種各樣類型的實(shí)際參數(shù),所以為了統(tǒng)一,采用直接父類數(shù)組Type[]進(jìn)行接收。
4. java.lang.reflect. GenericArrayType接口
GenericArrayType接口類型的含義
表示泛型數(shù)組類型。比如:void method(ArrayList[] al){…}
【注意】<>不能出現(xiàn)在數(shù)組的初始化中,即new數(shù)組之后不能出現(xiàn)<>,否則javac無法通過。但是作為引用變量或者方法的某個(gè)參數(shù)是完全可以的。
獲取泛型數(shù)組中元素的類型
源碼聲明:Type getGenericComponentType();
【注意】無論從左向右有幾個(gè)[]并列,這個(gè)方法僅僅脫去最右邊的[]之后剩下的內(nèi)容就作為這個(gè)方法的返回值。
為什么返回值類型是Type?
public static E methodV(
String[] p1,
E[] p2,
ArrayList[] p3,
E[][] p4){}
{1}. 對(duì)于String[],通過getComponentType()返回之后,脫去最右邊的[]之后,剩余的類型是String。因此對(duì)這個(gè)參數(shù)的返回類型是Class
{2}. 對(duì)于E[],通過getComponentType()返回之后,脫去最右邊的[]之后,剩余的類型是E。因此對(duì)這個(gè)參數(shù)的返回類型是TypeVariable
{3}. 對(duì)于ArrayList[],通過getComponentType()返回之后,脫去最右邊的[]之后,剩余的類型是ArrayList。因此對(duì)這個(gè)參數(shù)的返回類型是ParameterizedType
{4}. 對(duì)于E[][],通過getComponentType()返回之后,脫去最右邊的[]之后,剩余的類型是E[]。因此對(duì)這個(gè)參數(shù)的返回類型是GenericArrayType
5. java.lang.reflect. GenericArrayType接口
TypeVariable接口類型的含義
表示類型參數(shù)或者又叫做類型變量。比如:void method(E e){}中的E就是類型變量
獲取類型變量的泛型限定的上邊界的類型
源碼聲明:Type[] getActualTypeArguments();
【注意】這里面僅僅是上邊界。原因就是類型變量在定義的時(shí)候只能使用extends進(jìn)行(多)邊界限定。不能使用super,否則編譯無法通過。同時(shí)extends給出的都是類型變量的上邊界。
為什么是返回類型是數(shù)組?因?yàn)轭愋妥兞靠梢酝ㄟ^&進(jìn)行多個(gè)上邊界限定,因此上邊界有多個(gè),因此返回值類型是數(shù)組類型[ ]。
例如下面的方法:
public static extends Map& Cloneable&Serializable> E methodVI(E e){…}
E的第一個(gè)上邊界是Map,是ParameterizedType類型
E的第二個(gè)上邊界是Cloneable,是Class類型
因此,為統(tǒng)一,返回值的數(shù)組的元素類型就是Type
6. java.lang.reflect.WildcardType接口
WildcardType接口類型的含義
表示通配符類型的表達(dá)式。
比如 void printColl(ArrayListal); 中的 ? extends Number
【注意】根據(jù)上面API的注釋提示:現(xiàn)階段通配符表達(dá)式僅僅接受一個(gè)上邊界或者下邊界,這個(gè)和定義類型變量時(shí)候可以指定多個(gè)上邊界是不一樣。但是API說了,為了保持?jǐn)U展性,這里返回值類型寫成了數(shù)組形式。實(shí)際上現(xiàn)在返回的數(shù)組的大小就是1
獲取通配符表達(dá)式對(duì)象的泛型限定的上邊界的類型
源碼聲明:Type[] getUpperBounds();
【注意】上面說了,現(xiàn)階段返回的Type[ ]中的數(shù)組大小就是1個(gè)。寫成Type[ ]是為了語言的升級(jí)而進(jìn)行的擴(kuò)展。
例如下面的方法:
{1}. public static voidprintColl(ArrayListextends ArrayList> al){}
通配符表達(dá)式是:? extendsArrayList,這樣 extends后面是?的上邊界,這個(gè)上邊界是ParameterizedType類型。
{2}. public static voidprintColl(ArrayListextends E> al){}
通配符表達(dá)式是:? extends E,這樣 extends后面是?的上邊界,這個(gè)上邊界是TypeVariable類型
{3}.public static voidprintColl(ArrayListextends E[]> al){}
通配符表達(dá)式是:? extends E[],這樣 extends后面是?的上邊界,這個(gè)上邊界是GenericArrayType類型
{4}.public static voidprintColl(ArrayListextends Number> al){}
通配符表達(dá)式是:? extends Number,這樣 extends后面是?的上邊界,這個(gè)上邊界是Class類型
最終統(tǒng)一成Type作為數(shù)組的元素類型。
7. Type及其子接口的來歷
一. 泛型出現(xiàn)之前的類型
沒有泛型的時(shí)候,只有所謂的原始類型。此時(shí),所有的原始類型都通過字節(jié)碼文件類Class類進(jìn)行抽象。Class類的一個(gè)具體對(duì)象就代表一個(gè)指定的原始類型。
二. 泛型出現(xiàn)之后的類型
泛型出現(xiàn)之后,擴(kuò)充了數(shù)據(jù)類型。從只有原始類型擴(kuò)充了參數(shù)化類型、類型變量類型、泛型限定的的參數(shù)化類型 (含通配符+通配符限定表達(dá)式)、泛型數(shù)組類型。
三. 與泛型有關(guān)的類型不能和原始類型統(tǒng)一到Class的原因
[1]. 【產(chǎn)生泛型擦除的原因】
本來新產(chǎn)生的類型+原始類型都應(yīng)該統(tǒng)一成各自的字節(jié)碼文件類型對(duì)象。但是由于泛型不是最初Java中的成分。如果真的加入了泛型,涉及到JVM指令集的修改,這是非常致命的。
[2]. 【Java中如何引入泛型】
為了使用泛型的優(yōu)勢(shì)又不真正引入泛型,Java采用泛型擦除的機(jī)制來引入泛型。Java中的泛型僅僅是給編譯器javac使用的,確保數(shù)據(jù)的安全性和免去強(qiáng)制類型轉(zhuǎn)換的麻煩。但是,一旦編譯完成,所有的和泛型有關(guān)的類型全部擦除。
[3]. 【Class不能表達(dá)與泛型有關(guān)的類型】
因此,與泛型有關(guān)的參數(shù)化類型、類型變量類型、泛型限定的的參數(shù)化類型 (含通配符+通配符限定表達(dá)式)、泛型數(shù)組類型這些類型全部被打回原形,在字節(jié)碼文件中全部都是泛型被擦除后的原始類型,并不存在和自身類型一致的字節(jié)碼文件。所以和泛型相關(guān)的新擴(kuò)充進(jìn)來的類型不能被統(tǒng)一到Class類中。
(4). 與泛型有關(guān)的類型在Java中的表示
為了通過反射操作這些類型以迎合實(shí)際開發(fā)的需要,Java就新增了ParameterizedType,GenericArrayType,TypeVariable 和WildcardType幾種類型來代表不能被歸一到Class類中的類型但是又和原始類型齊名的類型。
(5). Type的引入:統(tǒng)一與泛型有關(guān)的類型和原始類型Class
【引入Type的原因】
為了程序的擴(kuò)展性,最終引入了Type接口作為Class,ParameterizedType,GenericArrayType,TypeVariable和WildcardType這幾種類型的總的父接口。這樣實(shí)現(xiàn)了Type類型參數(shù)接受以上五種子類的實(shí)參或者返回值類型就是Type類型的參數(shù)。
【Type接口中沒有方法的原因】
從上面看到,Type的出現(xiàn)僅僅起到了通過多態(tài)來達(dá)到程序擴(kuò)展性提高的作用,沒有其他的作用。因此Type接口的源碼中沒有任何方法。
相關(guān)文章
Java?集合框架掌握?Map?和?Set?的使用(內(nèi)含哈希表源碼解讀及面試??碱})
這篇文章主要介紹了Java?集合框架掌握?Map?和?Set?的使用并含有內(nèi)含哈希表源碼解讀及面試??碱},?Map?和?Set?是一種適合動(dòng)態(tài)查找的集合容器或者數(shù)據(jù)結(jié)構(gòu)下面文章詳細(xì)介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2021-12-12
Spring Boot利用Thymeleaf發(fā)送Email的方法教程
spring Boot默認(rèn)就是使用thymeleaf模板引擎的,下面這篇文章主要給大家介紹了關(guān)于在Spring Boot中利用Thymeleaf發(fā)送Email的方法教程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-08-08
springBoot 與neo4j的簡(jiǎn)單整合示例
這篇文章主要介紹了springBoot 與neo4j的簡(jiǎn)單整合示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01
SpringBoot Session共享實(shí)現(xiàn)圖解
這篇文章主要介紹了SpringBoot Session共享實(shí)現(xiàn)圖解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01
java設(shè)計(jì)模式學(xué)習(xí)之策略模式
這篇文章主要為大家詳細(xì)介紹了java設(shè)計(jì)模式學(xué)習(xí)之策略模式的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
詳解Spring Boot 定制HTTP消息轉(zhuǎn)換器
本篇文章主要介紹了詳解Spring Boot 定制HTTP消息轉(zhuǎn)換器,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11
Python單元測(cè)試_使用裝飾器實(shí)現(xiàn)測(cè)試跳過和預(yù)期故障的方法
下面小編就為大家?guī)硪黄狿ython單元測(cè)試_使用裝飾器實(shí)現(xiàn)測(cè)試跳過和預(yù)期故障的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06
Spring中DAO被循環(huán)調(diào)用的時(shí)候數(shù)據(jù)不實(shí)時(shí)更新的解決方法
這篇文章主要介紹了Spring中DAO被循環(huán)調(diào)用的時(shí)候數(shù)據(jù)不實(shí)時(shí)更新的解決方法,需要的朋友可以參考下2014-08-08
基于Lucene的Java搜索服務(wù)器Elasticsearch安裝使用教程
Elasticsearch也是用Java開發(fā)的,并作為Apache許可條款下的開放源碼發(fā)布,能夠做到實(shí)時(shí)搜索,且穩(wěn)定、可靠、快速,安裝使用方便,這里我們就來看一下基于Lucene的Java搜索服務(wù)器Elasticsearch安裝使用教程:2016-06-06
Java實(shí)現(xiàn)并發(fā)執(zhí)行定時(shí)任務(wù)并手動(dòng)控制開始結(jié)束
這篇文章主要介紹了Java實(shí)現(xiàn)并發(fā)執(zhí)行定時(shí)任務(wù)并手動(dòng)控制開始結(jié)束,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05

