一個(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ì)象類型存在多種,所以需要采用泛型。
這樣會(huì)存在一個(gè)需求,即將響應(yīng)結(jié)果轉(zhuǎn)換成相應(yīng)的類型。為了達(dá)到該需求,我們一般會(huì)再傳入一個(gè)Class來(lái)協(xié)助進(jìn)行類型轉(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,它的類型實(shí)際上就是參數(shù)reponseClass參數(shù)所表示的,為什么還要傳一個(gè)
Class<T> reponseClass
這個(gè)參數(shù),難道不能直接獲取到T所表示的Class嗎?
那么就引入了本篇要研究的主題,即如何在運(yùn)行時(shí)獲取泛型的類型。
最直接的嘗試:使用T.getClass()或者T.class。嘗試后發(fā)現(xiàn)T并沒(méi)有相應(yīng)的接口函數(shù)供使用
那就只能從實(shí)際的對(duì)象著手,即通過(guò)變量processResponseListener來(lái)取,因?yàn)閭魅氲氖菍?shí)際存在的對(duì)象,可以通過(guò)反射獲取泛型類型,改造一下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)行的類的字節(jié)碼
getGenericInterfaces():以Type數(shù)組的形式返回本類直接實(shí)現(xiàn)的接口列表,包含了泛型參數(shù)信息
getActualTypeArguments() :獲取泛型類型的實(shí)際類型參數(shù)集
另一種情況:
假設(shè)我們的監(jiān)聽(tīng)器不是一個(gè)接口,而是一個(gè)抽象類:
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ù)組的形式返回本類直接實(shí)現(xiàn)的接口列表,包含了泛型參數(shù)信息
很明顯傳入的AbstractProcessResponse<T>類型參數(shù)將是一個(gè)繼承該抽象類的子類,所以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í)體(類、接口、基本類型或 void)的直接超類的Type
最后總結(jié)一下:
對(duì)于實(shí)現(xiàn)接口而來(lái)的對(duì)象,使用getGenericInterfaces()與getActualTypeArguments()
對(duì)于繼承父類而來(lái)的對(duì)象,使用getGenericSuperclass()與getActualTypeArguments()