欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中獲取泛型類型信息的方法

 更新時(shí)間:2023年03月08日 09:56:18   作者:騎個(gè)小蝸牛  
本文主要介紹了Java中獲取泛型類型信息的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

根據(jù)使用泛型位置的不同可以分為:聲明側(cè)泛型、使用側(cè)泛型。

聲明側(cè)的泛型信息被記錄在Class文件的Constant pool中以Signature的形式保存。而使用側(cè)的泛型信息并沒(méi)有保存。

聲明側(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集合

  1. 若父類有泛型,返回的實(shí)際Type是ParameterizedType接口的實(shí)現(xiàn)類ParameterizedTypeImpl類
  2. 若父類無(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í)是沒(méi)辦法獲取到這些泛型信息的。

難道就真的沒(méi)辦法了嗎,其實(shí)還是有的。使用側(cè)需要獲取泛型信息的地方主要是:方法調(diào)用時(shí)傳入的泛型變量,通常需要在方法中獲取變量的泛型類型。比如在JSON解析(反序列化)的場(chǎng)景,他們是怎么實(shí)現(xiàn)的了。

針對(duì)獲取使用側(cè)的泛型類型信息,主要實(shí)現(xiàn)方案是通過(guò)匿名內(nèi)部類。

Gson中的泛型抽象類TypeToken<T>,F(xiàn)astJson中的泛型類TypeReference<T>等就是用的該方案。

匿名內(nèi)部類實(shí)現(xiàn)獲取使用側(cè)的泛型類型

上文有講到,在聲明側(cè)的泛型中,針對(duì)泛型類或泛型接口的聲明的泛型,Class類提供了getGenericSuperclass()、getGenericInterfaces()來(lái)獲取其子類(實(shí)現(xiàn)類)上聲明的具體泛型類型信息。

而匿名內(nèi)部類是什么?其本質(zhì)就是一個(gè)繼承/實(shí)現(xiàn)了某個(gè)類(接口,普通類,抽象類)的子類匿名對(duì)象。

匿名內(nèi)部類實(shí)現(xiàn)獲取使用側(cè)的泛型類型的原理:

  • 定義泛型類,泛型類中有一個(gè)Type類型的字段,用于保存泛型類型的Type
  • 通過(guò)匿名內(nèi)部類的方式創(chuàng)建該泛型類的子類實(shí)例(指定了具體的泛型類型)
    在創(chuàng)建子類實(shí)例的構(gòu)造方法中,已經(jīng)通過(guò)子類的Class的getGenericSuperclass()獲取到了泛型類型信息并復(fù)制給了Type類型的字段中。
  • 隨后任何地方,只要得到了該子類實(shí)例,就可以通過(guò)實(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)文章

  • Spark學(xué)習(xí)筆記(一)Spark初識(shí)【特性、組成、應(yīng)用】

    Spark學(xué)習(xí)筆記(一)Spark初識(shí)【特性、組成、應(yīng)用】

    這篇文章主要介紹了Spark學(xué)習(xí)筆記之Spark初識(shí),簡(jiǎn)單分析了spark四大特性、基本組成、應(yīng)用場(chǎng)景,需要的朋友可以參考下
    2020-02-02
  • 基于Spring AOP proxyTargetClass的行為表現(xiàn)總結(jié)

    基于Spring AOP proxyTargetClass的行為表現(xiàn)總結(jié)

    這篇文章主要介紹了Spring AOP proxyTargetClass的行為表現(xiàn)總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • springboot接口參數(shù)為L(zhǎng)ist的問(wèn)題

    springboot接口參數(shù)為L(zhǎng)ist的問(wèn)題

    這篇文章主要介紹了springboot接口參數(shù)為L(zhǎng)ist的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 聊一聊帶智能提示的spring-boot-starter

    聊一聊帶智能提示的spring-boot-starter

    這篇文章主要介紹了帶智能提示的spring-boot-starter的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2020-11-11
  • 通過(guò)實(shí)例解析java String不可變性

    通過(guò)實(shí)例解析java String不可變性

    這篇文章主要介紹了通過(guò)實(shí)例解析java String不可變性,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Spring Boot接收單個(gè)String入?yún)⒌慕鉀Q方法

    Spring Boot接收單個(gè)String入?yún)⒌慕鉀Q方法

    這篇文章主要給大家介紹了關(guān)于Spring Boot接收單個(gè)String入?yún)⒌慕鉀Q方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用spring boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • 深入了解為什么Java中只有值傳遞?

    深入了解為什么Java中只有值傳遞?

    這篇文章主要介紹了為什么 Java 中只有值傳遞?下面我們來(lái)簡(jiǎn)單了解一下吧
    2019-05-05
  • java獲取redis日志信息與動(dòng)態(tài)監(jiān)控信息的方法

    java獲取redis日志信息與動(dòng)態(tài)監(jiān)控信息的方法

    這篇文章主要給大家介紹了關(guān)于java如何獲取redis日志信息與動(dòng)態(tài)監(jiān)控信息的方法,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-04-04
  • SpringBoot深入探究四種靜態(tài)資源訪問(wèn)的方式

    SpringBoot深入探究四種靜態(tài)資源訪問(wèn)的方式

    這一節(jié)詳細(xì)的學(xué)習(xí)一下SpringBoot的靜態(tài)資源訪問(wèn)相關(guān)的知識(shí)點(diǎn)。像這樣的知識(shí)點(diǎn)還挺多,比如SpringBoot2的Junit單元測(cè)試等等。本章我們來(lái)了解靜態(tài)資源訪問(wèn)的四種方式
    2022-05-05
  • JavaSE實(shí)現(xiàn)電影院系統(tǒng)

    JavaSE實(shí)現(xiàn)電影院系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了JavaSE實(shí)現(xiàn)電影院系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08

最新評(píng)論