国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java 運行時如何獲取泛型參數的類型

2019-11-11 07:51:15
字體:
來源:轉載
供稿:網友

java 中對于下面最簡單的泛型類

class A<T> {	public void foo() {		//如何在此處獲得運行時 T 的具體類型呢?	}}

設想我們使用時

new A<String>().foo();

是否能在 foo() 方法中獲得當前的類型是 String 呢?答案是否定的,不能。在 foo() 方法中 this 引用給不出類型信息, this.getClass() 就更不可能了,因為 Java 的泛型不等同于 C++ 的模板類, this.getClass() 實例例是被所有的不同具體類型的 A 實例(new A<String>(), new A<Integer>() 等) 共享的,所以在字節碼中類型會被擦除到上限。

我們可以在 IDE 的調試時看到這個泛型類的簽名

或者用 javap -v cc.unmi.A 可以查看到類 A 的泛型簽名

Signature: #17                          // <T:Ljava/lang/Object;>Ljava/lang/Object;

為什么說是擦除到上限呢?并不是泛型在字節碼中都表示為 Object , 看下面的例子,假如 A 聲明如下

class A<T extends Number> {

}

再用 javap -v cc.unmi.A 來看泛型簽名

Signature: #18                          // <T:Ljava/lang/Number;>Ljava/lang/Object;

也就是說在上面的 foo() 方法中無法獲得當前的類型,我們必須給它加個參數 T

public void foo(T t) {

t.getClass();

}

了解了 Java 泛型機制是如何擦除類型的,我們接下來的問題就是如何通過反射獲得泛型簽名中的類型,一般會在繼承或實現泛型接口時會用到它。

繼承一個泛型基類
class A<T, ID> {}class B extends A<String, Integer> {}public class Generic {    public static void main(String[] args) {        System.out.PRintln(B.class.getGenericSuperclass());    }}

上面的代碼輸出是

cc.unmi.A<java.lang.String, java.lang.Integer>

所以要獲得這兩個類型是可行的,設置了斷點

這張圖可以看到 B.class.getGenericSuperclass() 得到的實際類型是 ParameterizedTypeImpl 通過它就可以獲得 actualTypeArguments 了。代碼就是

ParameterizedType parameterizedType = (ParameterizedType) B.class.getGenericSuperclass();Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for(Type actualTypeArgument: actualTypeArguments) {    System.out.println(actualTypeArgument);}

上面的代碼輸出

class java.lang.String

class java.lang.Integer

我們不妨用 javap -v cc.unmi.B 的泛型簽名

Signature: #12                          // Lcc/unmi/A<Ljava/lang/String;Ljava/lang/Integer;>;

實現一個泛型接口

這時與繼承一個泛型基類的情況略有不同,如下關系,A 是一個泛型接口

interface A<T, ID> {}class B implements A<String, Integer> {}

該如何反射獲得 B 的參數類型呢,用上面的方法已不可行, B.class.getGenericSuperclass() 已不是一個 ParameterizedTypeImpl 而是一個 Object 類型。現在需要另一個方法 getGenericInterfaces(): Type[] 它得到一個 Type 數組,代表類實現的多個接口,因為我們這兒只實現了一個接口,所以取第一個元素,它的類型是我們已見過的 ParameterizedTypeImpl ,

因此我們用來獲得實現接口而來的泛型參數的代碼就是

ParameterizedType parameterizedType = (ParameterizedType) B.class.getGenericInterfaces()[0];Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {    System.out.println(actualTypeArgument);}

同樣能得到上面的一樣的結果。

總結一下

如果是繼承基類而來的泛型,就用 getGenericSuperclass() , 轉型為 ParameterizedType 來獲得實際類型如果是實現接口而來的泛型,就用 getGenericInterfaces() , 針對其中的元素轉型為 ParameterizedType 來獲得實際類型我們所說的 Java 泛型在字節碼中會被擦除,并不總是擦除為 Object 類型,而是擦除到上限類型能否獲得想要的類型可以在 IDE 中,或用 javap -v <your_class>   來查看泛型簽名來找到線索
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 聂拉木县| 辽宁省| 天水市| 佛山市| 乌拉特中旗| 尚志市| 孝感市| 逊克县| 万盛区| 调兵山市| 张北县| 宁海县| 灵宝市| 武宁县| 临湘市| 新泰市| 浮梁县| 临潭县| 江永县| 鄯善县| 虞城县| 保山市| 桐乡市| 临猗县| 铜川市| 蛟河市| 武清区| 惠水县| 松原市| 高平市| 姜堰市| 常州市| 如皋市| 宁河县| 雅江县| 西城区| 雅江县| 礼泉县| 合阳县| 永胜县| 读书|