在泛型中得到T.class
在使用Spring的JdbcTemplate實現DAO的時候,經常會用到一個類ParameterizedBeanPropertyRowMapper。它的靜態方法newInstance()接受一個Class型別的引數,用於將ResultSet中的屬性對映到傳入的這個Class型別的Bean物件中,再組成列表返回。
如果要想把這個DAO做成泛型的,就必須要知道Class的型別。但是直接寫成T.class顯然是不行的。從網上查了不少資料,結果只有一個,由於Java的泛型實現使用了“擦拭法”(具體細節沒深究,呵呵),導致Java的泛型不能直接獲取到自身的宣告的泛型型別。
不過從江南白衣的blog文章裡搜到了有用的東西:使用反射來獲得“T.class”。
原文地址:http://www.blogjava.net/calvin/archive/2009/12/10/43830.html
主要用到的是這麼一句:
view plaincopy to clipboardprint?
Class <T> entityClass = (Class <T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
Class <T> entityClass = (Class <T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
我查詢了Java API,在Class類中有這麼兩個方法: getGenericInterfaces()和getGenericSuperclass()
先來看看這兩個方法都是幹什麼用的:
1. public Type getGenericSuperclass()
用來返回表示當前Class 所表示的實體(類、介面、基本型別或 void)的直接超類的Type。如果這個直接超類是引數化型別的,則返回的Type物件必須明確反映在原始碼中宣告時使用的型別。比如:
view plaincopy to clipboardprint?
package com.mot.hyena.test;
import java.lang.reflect.ParameterizedType;
public class GT1 extends GT2<Integer>{
public static void main(String[] args) {
System.out.println(((ParameterizedType)new GT1().getClass().getGenericSuperclass()));
}
}
package com.mot.hyena.test;
import java.lang.reflect.ParameterizedType;
public class GT1 extends GT2<Integer>{
public static void main(String[] args) {
System.out.println(((ParameterizedType)new GT1().getClass().getGenericSuperclass()));
}
}
則輸出結果即為:com.mot.hyena.test.GT2<java.lang.Integer>
如果此Class代表的是Object 類、介面、基本型別或 void,則返回 null。。如果此物件表示一個陣列類,則返回表示 Object 類的 Class 物件。
2. public Type[] getGenericInterfaces()
與上面那個方法類似,只不過Java的類可以實現多個介面,所以返回的Type必須用陣列來儲存。
以上兩個方法返回的都是Type物件或陣列,在我們的這個話題中,Class都是代表的引數化型別,因此可以將Type物件Cast成ParameterizedType物件。而 ParameterizedType物件有一個方法, getActualTypeArguments()。
public Type[] getActualTypeArguments()
用來返回一個Type物件陣列,這個陣列代表著這個Type宣告中實際使用的型別。接著使用上面的例子:
view plaincopy to clipboardprint?
package com.mot.hyena.test;
import java.lang.reflect.ParameterizedType;
public class GT1 extends GT2<Integer>{
public static void main(String[] args) {
System.out.println(((ParameterizedType)new GT1().getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
}
}
package com.mot.hyena.test;
import java.lang.reflect.ParameterizedType;
public class GT1 extends GT2<Integer>{
public static void main(String[] args) {
System.out.println(((ParameterizedType)new GT1().getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
}
}
這次的顯示結果將是:class java.lang.Integer
因此,我們可以通過繼承+反射的方法,來的到T.class。
需要說明的是,江南白衣使用的方法是將關鍵語句
Class < T > entityClass = (Class < T > ) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[ 0 ];
放在了超類,也就是宣告泛型的那個類的構造方法中。這樣一來,子類在繼承具有泛型的超類時,會自動呼叫超類的構造方法。在此超類的構造方法中,呼叫的getClass返回的是子類的Class型別(與通常的重寫機制有悖,呵呵,有待深究,但測試結果確是如此),則在子類中就無需再顯式地使用 getGenericInterfaces()和getGenericSuperclass()等方法了。
接著,再使用(Class<T>)對 getActualTypeArguments()返回的元素做casting,即可得到所謂的T.class。
相關文章
- 【譯】在非泛型類中建立泛型方法泛型
- Java5泛型的用法,T.class的獲取和為擦拭法Java泛型
- 預計在 Go 1.18 中內建泛型Go泛型
- NET 2.0中泛型泛型
- Java中的泛型Java泛型
- Java泛型知識點:泛型類、泛型介面和泛型方法Java泛型
- Kotlin中的泛型Kotlin泛型
- Java中的泛型方法Java泛型
- Swift 4 中的泛型Swift泛型
- Swift 中的泛型使用Swift泛型
- 泛型類、泛型方法及泛型應用泛型
- 泛型類和泛型方法泛型
- 【java】【泛型】泛型geneticJava泛型
- java泛型之泛型方法。Java泛型
- 泛型--泛型萬用字元和泛型的上下限泛型字元
- C#中的泛型-1C#泛型
- Java 中泛型的協變Java泛型
- Java 中泛型的全面解析Java泛型
- 深入解析Java中的泛型Java泛型
- java中泛型之型別萬用字元(?)Java泛型型別字元
- Java中建立泛型型別的例項Java泛型型別
- TypeScript 泛型介面和泛型類TypeScript泛型
- Go 泛型之泛型約束Go泛型
- java泛型之泛型陣列。Java泛型陣列
- Java中泛型的詳細解析,深入分析泛型的使用方式Java泛型
- 泛型泛型
- 在Golang中使用泛型從任何map中獲取鍵的sliceGolang泛型
- Kotlin 泛型中的 in 和 outKotlin泛型
- Java 中的泛型方法及 FunctionJava泛型Function
- Java 泛型中易混淆的地方Java泛型
- Java 泛型中的萬用字元Java泛型字元
- 泛型中的自限定型別泛型型別
- HarmonyOS 專案中泛型的使用泛型
- 泛型最佳實踐:Go泛型設計者教你如何用泛型泛型Go
- 在Golang中使用泛型reduce函式 - gosamplesGolang泛型函式
- 在feign介面中返回泛型類(Generic response support for feign client)泛型client
- 型別 VS 泛型型別泛型
- TypeScript 泛型型別TypeScript泛型型別