Java中獲取泛型類型信息的方法
根據(jù)使用泛型位置的不同可以分為:聲明側(cè)泛型、使用側(cè)泛型。
聲明側(cè)的泛型信息被記錄在Class文件的Constant pool中以Signature的形式保存。而使用側(cè)的泛型信息并沒有保存。
聲明側(cè)泛型
聲明側(cè)泛型包括:
- 泛型類,或泛型接口的聲明
- 帶有泛型參數(shù)的成員變量
- 帶有泛型參數(shù)的方法
使用側(cè)泛型
使用側(cè)泛型包括:
- 方法的局部變量,
- 方法調(diào)用時(shí)傳入的變量
獲取泛型類型相關(guān)方法
上文有提到,聲明側(cè)的泛型被記錄在Class文件的Constant pool中以Signature的形式保存。
JDK的Class、Field、Method類提供了一系列的獲取泛型類型的相關(guān)方法。
1. Class類的泛型方法
Type getGenericSuperclass():獲取父類的Type
- 若父類有泛型,返回的實(shí)際Type是ParameterizedType接口的實(shí)現(xiàn)類ParameterizedTypeImpl類
- 若父類無(wú)泛型,返回的實(shí)際Type是Class類
Type[] getGenericInterfaces():獲取父接口的Type集合
- 若父類有泛型,返回的實(shí)際Type是ParameterizedType接口的實(shí)現(xiàn)類ParameterizedTypeImpl類
- 若父類無(wú)泛型,返回的實(shí)際Type是Class類
2. Field類的泛型方法
Type getGenericType():獲取字段的Type
- 若字段有泛型,返回的實(shí)際Type是ParameterizedType接口的實(shí)現(xiàn)類ParameterizedTypeImpl類
- 若字段無(wú)泛型,返回的實(shí)際Type是Class類
3. Method類的泛型方法
Type getGenericReturnType():獲取方法返回值的Type
- 若返回值有泛型,返回的實(shí)際Type是ParameterizedType接口的實(shí)現(xiàn)類ParameterizedTypeImpl類
- 若返回值無(wú)泛型,返回的實(shí)際Type是Class類
Type[] getGenericParameterTypes():獲取方法參數(shù)的Type集合
- 若方法參數(shù)有泛型,返回的實(shí)際Type是ParameterizedType接口的實(shí)現(xiàn)類ParameterizedTypeImpl類
- 若方法參數(shù)無(wú)泛型,返回的實(shí)際Type是Class類
Type[] getGenericExceptionTypes():獲取方法聲明的異常的Type集合
- 若方法參數(shù)有泛型,返回的實(shí)際Type是ParameterizedType接口的實(shí)現(xiàn)類ParameterizedTypeImpl類
- 若方法參數(shù)無(wú)泛型,返回的實(shí)際Type是Class類
4. ParameterizedType類
ParameterizedType是Type的子接口,表示參數(shù)化類型,用于獲取泛型的參數(shù)類型。
ParameterizedType的主要方法:
- Type[] getActualTypeArguments():獲取實(shí)際類型參數(shù)的Type集合
- Type getRawType():獲取聲明此類型的類或接口的Type
- Type getOwnerType():如果聲明此類型的類或接口為內(nèi)部類,這返回的是該內(nèi)部類的外部類的Type(也就是該內(nèi)部類的擁有者)
獲取聲明側(cè)的泛型類型信息
- 泛型類,或泛型接口的聲明
- 帶有泛型參數(shù)的成員變量
- 帶有泛型參數(shù)的方法
示例:
public class MyTest extends TestClass<String> implements TestInterface1<Integer>,TestInterface2<Long> {
? ? private List<Integer> list;
? ? private Map<Integer, String> map;
? ? public List<String> aa() {
? ? ? ? return null;
? ? }
? ? public void bb(List<Long> list) {
? ? }
? ? public static void main(String[] args) throws Exception {
? ? ? ? System.out.println("======================================= 泛型類聲明的泛型類型 =======================================");
? ? ? ? ParameterizedType parameterizedType = (ParameterizedType)MyTest.class.getGenericSuperclass();
? ? ? ? System.out.println(parameterizedType.getTypeName() + "--------->" + parameterizedType.getActualTypeArguments()[0].getTypeName());
? ? ? ? Type[] types = MyTest.class.getGenericInterfaces();
? ? ? ? for (Type type : types) {
? ? ? ? ? ? ParameterizedType typ = (ParameterizedType)type;
? ? ? ? ? ? System.out.println(typ.getTypeName() + "--------->" + typ.getActualTypeArguments()[0].getTypeName());
? ? ? ? }
? ? ? ? System.out.println("======================================= 成員變量中的泛型類型 =======================================");
? ? ? ? ParameterizedType parameterizedType1 = (ParameterizedType)MyTest.class.getDeclaredField("list").getGenericType();
? ? ? ? System.out.println(parameterizedType1.getTypeName() + "--------->" + parameterizedType1.getActualTypeArguments()[0].getTypeName());
? ? ? ? ParameterizedType parameterizedType2 = (ParameterizedType)MyTest.class.getDeclaredField("map").getGenericType();
? ? ? ? System.out.println(parameterizedType2.getTypeName() + "--------->" + parameterizedType2.getActualTypeArguments()[0].getTypeName()+","+parameterizedType2.getActualTypeArguments()[1].getTypeName());
? ? ? ? System.out.println("======================================= 方法參數(shù)中的泛型類型 =======================================");
? ? ? ? ParameterizedType parameterizedType3 = (ParameterizedType)MyTest.class.getMethod("aa").getGenericReturnType();
? ? ? ? System.out.println(parameterizedType3.getTypeName() + "--------->" + parameterizedType3.getActualTypeArguments()[0].getTypeName());
? ? ? ? System.out.println("======================================= 方法返回值中的泛型類型 =======================================");
? ? ? ? Type[] types1 = MyTest.class.getMethod("bb", List.class).getGenericParameterTypes();
? ? ? ? for (Type type : types1) {
? ? ? ? ? ? ParameterizedType typ = (ParameterizedType)type;
? ? ? ? ? ? System.out.println(typ.getTypeName() + "--------->" + typ.getActualTypeArguments()[0].getTypeName());
? ? ? ? }
? ? }
}
class TestClass<T> {
}
interface TestInterface1<T> {
}
interface TestInterface2<T> {
}輸出
======================================= 泛型類聲明的泛型類型 =======================================
com.joker.test.generic.TestClass<java.lang.String>--------->java.lang.String
com.joker.test.generic.TestInterface1<java.lang.Integer>--------->java.lang.Integer
com.joker.test.generic.TestInterface2<java.lang.Long>--------->java.lang.Long
======================================= 成員變量中的泛型類型 =======================================
java.util.List<java.lang.Integer>--------->java.lang.Integer
java.util.Map<java.lang.Integer, java.lang.String>--------->java.lang.Integer,java.lang.String
======================================= 方法參數(shù)中的泛型類型 =======================================
java.util.List<java.lang.String>--------->java.lang.String
======================================= 方法返回值中的泛型類型 =======================================
java.util.List<java.lang.Long>--------->java.lang.Long
獲取使用側(cè)的泛型類型信息
上面講的相關(guān)類的獲取泛型類型相關(guān)方法都只是針對(duì)聲明側(cè)的泛型。因?yàn)槁暶鱾?cè)的泛型被記錄在Class文件的Constant pool中以Signature的形式保存。所以Java提供了相關(guān)方法能獲取到這些信息。
那使用側(cè)的泛型信息怎么獲取呢?由于使用側(cè)的泛型信息在編譯期的時(shí)候就被類型擦除了,所以運(yùn)行時(shí)是沒辦法獲取到這些泛型信息的。
難道就真的沒辦法了嗎,其實(shí)還是有的。使用側(cè)需要獲取泛型信息的地方主要是:方法調(diào)用時(shí)傳入的泛型變量,通常需要在方法中獲取變量的泛型類型。比如在JSON解析(反序列化)的場(chǎng)景,他們是怎么實(shí)現(xiàn)的了。
針對(duì)獲取使用側(cè)的泛型類型信息,主要實(shí)現(xiàn)方案是通過匿名內(nèi)部類。
Gson中的泛型抽象類TypeToken<T>,F(xiàn)astJson中的泛型類TypeReference<T>等就是用的該方案。
匿名內(nèi)部類實(shí)現(xiàn)獲取使用側(cè)的泛型類型
上文有講到,在聲明側(cè)的泛型中,針對(duì)泛型類或泛型接口的聲明的泛型,Class類提供了getGenericSuperclass()、getGenericInterfaces()來獲取其子類(實(shí)現(xiàn)類)上聲明的具體泛型類型信息。
而匿名內(nèi)部類是什么?其本質(zhì)就是一個(gè)繼承/實(shí)現(xiàn)了某個(gè)類(接口,普通類,抽象類)的子類匿名對(duì)象。
匿名內(nèi)部類實(shí)現(xiàn)獲取使用側(cè)的泛型類型的原理:
- 定義泛型類,泛型類中有一個(gè)Type類型的字段,用于保存泛型類型的Type
- 通過匿名內(nèi)部類的方式創(chuàng)建該泛型類的子類實(shí)例(指定了具體的泛型類型)
在創(chuàng)建子類實(shí)例的構(gòu)造方法中,已經(jīng)通過子類的Class的getGenericSuperclass()獲取到了泛型類型信息并復(fù)制給了Type類型的字段中。 - 隨后任何地方,只要得到了該子類實(shí)例,就可以通過實(shí)例得到泛型類型的Type,這就得到了使用側(cè)的泛型類信息。
簡(jiǎn)單示例:
定義泛型類TestClass2<T>,類中包含字段Type
public abstract class TestClass2<T> {
? ? private final Type type;
? ? public TestClass2() {
? ? ? ? Type superClass = getClass().getGenericSuperclass();
? ? ? ? if (!(superClass instanceof ParameterizedType)) {
? ? ? ? ? ? throw new IllegalArgumentException("無(wú)泛型類型信息");
? ? ? ? }
? ? ? ? type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
? ? }
? ? public Type getType() {
? ? ? ? return type;
? ? }
}測(cè)試獲取泛型類型
public class Test {
? ? public static ?<T> T get(TestClass2<T> tTestClass2) throws IllegalAccessException, InstantiationException {
? ? ? ? Type type = tTestClass2.getType();
? ? ? ? Class clazz = (Class) type;
? ? ? ? return (T)clazz.newInstance();
? ? }
? ? public static void main(String[] args) throws InstantiationException, IllegalAccessException {
? ? ? ? String str = get(new TestClass2<String>() {});
? ? ? ? Date date = get(new TestClass2<Date>() {});
? ? }
}到此這篇關(guān)于Java中獲取泛型類型信息的方法的文章就介紹到這了,更多相關(guān)Java獲取泛型類型信息內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java微服務(wù)Nacos Config配置中心超詳細(xì)講解
配置文件相對(duì)分散。在一個(gè)微服務(wù)架構(gòu)下,配置文件會(huì)隨著微服務(wù)的增多變的越來越多,而且分散 在各個(gè)微服務(wù)中,不好統(tǒng)一配置和管理。每一個(gè)環(huán)境所使用的配置理論上都是不同的,一旦需要修改,就需要我們?nèi)ジ鱾€(gè)微服務(wù)下手動(dòng)維護(hù)2023-02-02
maven?插件?assembly?打tar.gz包的詳細(xì)過程
這篇文章主要介紹了maven插件assembly打tar.gz包的詳細(xì)過程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06
Spring Cloud Zuul集成Swagger實(shí)現(xiàn)過程解析
這篇文章主要介紹了Spring Cloud Zuul集成Swagger實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
mybatis一級(jí)緩存和二級(jí)緩存的區(qū)別及說明
這篇文章主要介紹了mybatis一級(jí)緩存和二級(jí)緩存的區(qū)別及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
java實(shí)現(xiàn)6種字符串?dāng)?shù)組的排序(String array sort)
這篇文章主要介紹了java實(shí)現(xiàn)6種字符串?dāng)?shù)組的排序(String array sort),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01
SpringBoot整合Ureport2報(bào)表及常見使用方法
這篇文章主要介紹了SpringBoot整合Ureport2報(bào)表及常見使用方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
SpringBoot+MybatisPlus+Mysql+Sharding-JDBC分庫(kù)分表
本文主要介紹了SpringBoot+MybatisPlus+Mysql+Sharding-JDBC分庫(kù)分表,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
mybatis@insert?注解如何判斷insert或是update
這篇文章主要介紹了mybatis@insert?注解如何判斷insert或是update,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07

