Java如何獲得泛型類中的泛型類型T.class
Java獲得泛型類的泛型類型T.class
假如我們寫(xiě)了1個(gè)泛型類MyBase
public class MyBase<E> {
public MyBase(){
}
public Class<?> getEClass() {
?
}
}我想寫(xiě)1個(gè)getEClass 的方法, 獲取泛型符號(hào)E的Class對(duì)象。
直接用E.class E.getClass()都是不合法的, 因?yàn)镋只是個(gè)符號(hào), 沒(méi)有被實(shí)例化。
1. 反射方案
各種google 各種Stackoverflow 后, 找到利用反射的1個(gè)方法。
public class MyBase<E> {
public MyBase(){
}
public Class<?> getEClass() {
//get the Class object of this own class
Class<? extends MyBase> thisClass = this.getClass();
//get the Type Object of supper class
Type superClassType = thisClass.getGenericSuperclass();
ParameterizedType pt = (ParameterizedType)superClassType;
//get the Generic Type array
Type[] genTypeArr = pt.getActualTypeArguments();
Type genType = genTypeArr[0];
if (false == genType instanceof Class){
return Object.class;
}
return (Class<Object>) genType;
}
}這個(gè)方法被測(cè)試過(guò), 但是有個(gè)很特別的限制,
一定要實(shí)例化匿名子類才有效果。
例如:
@Test
void testMyBase() {
MyBase<String> mybase = new MyBase<String>(){};
log.info("E class is {}",mybase.getEClass());
}注意new MyBase(){} 后面的大括號(hào), 意思不是實(shí)例化MyBase對(duì)象, 而是實(shí)例化MyBase的匿名子類。
如果我們寫(xiě)多1個(gè)具體的子類MyList
public class MyList<E> extends MyBase<E> {
public MyList(){
}
}測(cè)試方法:
@Test
void testGetEClass() {
MyList<String> mylist = new MyList<String>();
log.info("E class is {}",mylist.getEClass());
}同樣不行, 原因是
//get the Type Object of supper class
Type superClassType = thisClass.getGenericSuperclass();
ParameterizedType pt = (ParameterizedType)superClassType;這里 我們只能通過(guò)本類的Class對(duì)象去獲得1個(gè)父類 ParameterizedType (包括泛型參數(shù)列表的Type)
而JDK本身只提供了getGenericSuperclass()方法去獲得父類的Type 對(duì)象
但是沒(méi)有提供例如getGenericClass() 去獲取本類的Type對(duì)象…
所以一旦我們不實(shí)用匿名子類
當(dāng)下面代碼被執(zhí)行時(shí)
MyList<String> mylist = new MyList<String>();
log.info("E class is {}",mylist.getEClass());thisClass.getGenericSuperclass() 會(huì)獲得MyList的父類MyBase的Type, 問(wèn)題是MyBase沒(méi)有被實(shí)例化, 所以pt.getActualTypeArguments()[0] 只會(huì)返回E
本身 就return null了
但是如果我們利用匿名子類的化
當(dāng)下面代碼被執(zhí)行時(shí)
MyList<String> mylist = new MyList<String>(){};
log.info("E class is {}",mylist.getEClass());mylist 的類實(shí)際上是1個(gè)匿名子類MyList$1, 它的父類就是MyList, 而匿名子類的父類在JVM實(shí)際上是被實(shí)例化的
所以pt.getActualTypeArguments()[0] 會(huì)返回泛型具體類String 的Class。
2. 反射方案2
匿名子類畢竟有點(diǎn)奇怪。
如果避免使用你匿名子類, 我們還有1個(gè)辦法
public class MySet extends MyBase<String> {
public MySet(){
}
}如上面這個(gè)MySet類, 它直接繼承MyBase時(shí)指定了具體泛型, 令到自己本身不是1個(gè)泛型類。
這樣的話, 不用匿名子類也一樣可以獲得泛型具體類型。
因?yàn)檫@種情況下, 一旦實(shí)現(xiàn)MySet, 因?yàn)镸ySet指定了繼承泛型的具體類型, 在JVM 中MyBase也會(huì)被實(shí)例化。
但是這個(gè)方案一樣不好, 不靈活是其次, 我都會(huì)指定了具體泛型類型了, 何必用再用getEClass()去獲得泛型具體類型? 多次一舉
@Test
void testGetEClass2() {
MySet myset = new MySet();
log.info("Set E class is {}",myset.getEClass());
}3. 構(gòu)造方法方案
這也是外網(wǎng)強(qiáng)烈推薦的方案
public class MyMap<E> {
private Class<E> eClass;
public MyMap(Class<E> eClass){
this.eClass = eClass;
}
public Class<E> getEClass(){
return this.eClass;
}
}讓開(kāi)發(fā)人員在初始化時(shí),順便外部傳入泛型的類, 不過(guò)手抖寫(xiě)錯(cuò)的風(fēng)險(xiǎn)…
測(cè)試方法:
@Test
void testGetEClass3() {
MyMap<String> myMap= new MyMap<>(String.class);
log.info("Set E class is {}",myMap.getEClass());
}
}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java 按照字節(jié)來(lái)截取字符串的代碼(不會(huì)出現(xiàn)半個(gè)漢字)
Java 按照字節(jié)來(lái)截取字符串的工具,不會(huì)出現(xiàn)半個(gè)漢字。一個(gè)中文兩個(gè)字節(jié),一個(gè)英文字符只占 1 個(gè)字節(jié)** 1. 通常我們用于前端顯示的時(shí)候,防止標(biāo)題過(guò)長(zhǎng)2014-01-01
SpringCloud將Nacos作為配置中心實(shí)現(xiàn)流程詳解
這篇文章主要介紹了Springcloud中的Nacos Config服務(wù)配置,本文以用戶微服務(wù)為例,進(jìn)行統(tǒng)一的配置,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-10-10
Spring context:component-scan的使用及說(shuō)明
這篇文章主要介紹了Spring context:component-scan的使用及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
Springboot項(xiàng)目對(duì)數(shù)據(jù)庫(kù)用戶名密碼實(shí)現(xiàn)加密過(guò)程解析
這篇文章主要介紹了Springboot項(xiàng)目對(duì)數(shù)據(jù)庫(kù)用戶名密碼實(shí)現(xiàn)加密過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06

