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