一個(gè)簡(jiǎn)單場(chǎng)景:一個(gè)處理函數(shù)家破,需要傳入處理結(jié)果監(jiān)聽(tīng)來(lái)響應(yīng)結(jié)果仓坞,響應(yīng)結(jié)果是一個(gè)JSON字符串背零,且要將其轉(zhuǎn)換成對(duì)象再交給監(jiān)聽(tīng)進(jìn)行處理,由于對(duì)象類(lèi)型存在多種无埃,所以需要采用泛型徙瓶。
這樣會(huì)存在一個(gè)需求,即將響應(yīng)結(jié)果轉(zhuǎn)換成相應(yīng)的類(lèi)型录语。為了達(dá)到該需求倍啥,我們一般會(huì)再傳入一個(gè)Class來(lái)協(xié)助進(jìn)行類(lèi)型轉(zhuǎn)換
結(jié)果響應(yīng)監(jiān)聽(tīng)器:
public interface IProcessResponse<T> {
public void onProcessCompleted(T result);
}
處理函數(shù):
public class Test {
public <T> void process(Class<T> reponseClass
,IProcessResponse<T> processResponseListener){
String content = runProcess();
Gson gson = new Gson();
T responese = gson.fromJson(content, reponseClass);
processResponseListener.onProcessCompleted(responese);
}
}
這樣處理很好,沒(méi)有什么問(wèn)題澎埠,但是我有一個(gè)疑問(wèn)虽缕,既然監(jiān)聽(tīng)器里已經(jīng)帶了T,它的類(lèi)型實(shí)際上就是參數(shù)reponseClass參數(shù)所表示的蒲稳,為什么還要傳一個(gè)
Class<T> reponseClass
這個(gè)參數(shù)氮趋,難道不能直接獲取到T所表示的Class嗎?
那么就引入了本篇要研究的主題江耀,即如何在運(yùn)行時(shí)獲取泛型的類(lèi)型剩胁。
最直接的嘗試:使用T.getClass()或者T.class。嘗試后發(fā)現(xiàn)T并沒(méi)有相應(yīng)的接口函數(shù)供使用
那就只能從實(shí)際的對(duì)象著手祥国,即通過(guò)變量processResponseListener來(lái)取昵观,因?yàn)閭魅氲氖菍?shí)際存在的對(duì)象,可以通過(guò)反射獲取泛型類(lèi)型舌稀,改造一下process函數(shù):
public <T> void process(IProcessResponse<T> processResponseListener){
String content = runProcess();
Gson gson = new Gson();
Type[] types = processResponseListener.getClass().getGenericInterfaces();
Type[] params = ((ParameterizedType) types[0]).getActualTypeArguments();
Class<T> reponseClass = (Class) params[0];
T responese = gson.fromJson(content, reponseClass);
processResponseListener.onProcessCompleted(responese);
}
getClass():獲取的是實(shí)際運(yùn)行的類(lèi)的字節(jié)碼
getGenericInterfaces():以Type數(shù)組的形式返回本類(lèi)直接實(shí)現(xiàn)的接口列表啊犬,包含了泛型參數(shù)信息
getActualTypeArguments() :獲取泛型類(lèi)型的實(shí)際類(lèi)型參數(shù)集
另一種情況:
假設(shè)我們的監(jiān)聽(tīng)器不是一個(gè)接口,而是一個(gè)抽象類(lèi):
public abstract class AbstractProcessResponse<T> {
public abstract void onProcessCompleted(T result);
private void commonProcess(){}
}
處理函數(shù)直接仿造 :
public <T> void process(IProcessResponse<T> processResponseListener)
函數(shù)壁查,得到:
public <T> void process(AbstractProcessResponse<T> processResponseListener){
String content = runProcess();
Gson gson = new Gson();
Type[] types = processResponseListener.getClass().getGenericInterfaces();
Type[] params = ((ParameterizedType) types[0]).getActualTypeArguments();
Class<T> reponseClass = (Class) params[0];
T responese = gson.fromJson(content, reponseClass);
processResponseListener.onProcessCompleted(responese);
}
上面能得到正確結(jié)果嗎觉至?看getGenericInterfaces()方法的作用:
???? 以Type數(shù)組的形式返回本類(lèi)直接實(shí)現(xiàn)的接口列表,包含了泛型參數(shù)信息
很明顯傳入的AbstractProcessResponse<T>類(lèi)型參數(shù)將是一個(gè)繼承該抽象類(lèi)的子類(lèi)睡腿,所以getGenericInterfaces()取到的Type[]數(shù)組元素個(gè)數(shù)為0语御,上面的函數(shù)執(zhí)行將會(huì)拋出異常
?? 經(jīng)改造峻贮,正確的函數(shù)如下:
public <T> void process(AbstractProcessResponse<T> processResponseListener){
String content = runProcess();
Gson gson = new Gson();
Type type = processResponseListener.getClass().getGenericSuperclass();
Type[] params = ((ParameterizedType) type).getActualTypeArguments();
Class<T> reponseClass = (Class) params[0];
T responese = gson.fromJson(content, reponseClass);
processResponseListener.onProcessCompleted(responese);
}
getGenericSuperclass() :返回表示當(dāng)前Class 所表示的實(shí)體(類(lèi)逗载、接口兽赁、基本類(lèi)型或 void)的直接超類(lèi)的Type
最后總結(jié)一下:
對(duì)于實(shí)現(xiàn)接口而來(lái)的對(duì)象桂躏,使用getGenericInterfaces()與getActualTypeArguments()
對(duì)于繼承父類(lèi)而來(lái)的對(duì)象惹想,使用getGenericSuperclass()與getActualTypeArguments()