一個簡單場景:一個處理函數,需要傳入處理結果監聽來響應結果,響應結果是一個JSON字符串,且要將其轉換成對象再交給監聽進行處理,由于對象類型存在多種,所以需要采用泛型。
這樣會存在一個需求,即將響應結果轉換成相應的類型。為了達到該需求,我們一般會再傳入一個Class來協助進行類型轉換
結果響應監聽器:
public interface IProcessResponse<T> {
public void onProcessCompleted(T result);
}
處理函數:
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);
}
}
這樣處理很好,沒有什么問題,但是我有一個疑問,既然監聽器里已經帶了T,它的類型實際上就是參數reponseClass參數所表示的,為什么還要傳一個
Class<T> reponseClass
這個參數,難道不能直接獲取到T所表示的Class嗎?
那么就引入了本篇要研究的主題,即如何在運行時獲取泛型的類型。
最直接的嘗試:使用T.getClass()或者T.class。嘗試后發現T并沒有相應的接口函數供使用
那就只能從實際的對象著手,即通過變量processResponseListener來取,因為傳入的是實際存在的對象,可以通過反射獲取泛型類型,改造一下process函數:
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():獲取的是實際運行的類的字節碼
getGenericInterfaces():以Type數組的形式返回本類直接實現的接口列表,包含了泛型參數信息
getActualTypeArguments() :獲取泛型類型的實際類型參數集
另一種情況:
假設我們的監聽器不是一個接口,而是一個抽象類:
public abstract class AbstractProcessResponse<T> {
public abstract void onProcessCompleted(T result);
private void commonProcess(){}
}
處理函數直接仿造 :
public <T> void process(IProcessResponse<T> processResponseListener)
函數,得到:
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);
}
上面能得到正確結果嗎?看getGenericInterfaces()方法的作用:
???? 以Type數組的形式返回本類直接實現的接口列表,包含了泛型參數信息
很明顯傳入的AbstractProcessResponse<T>類型參數將是一個繼承該抽象類的子類,所以getGenericInterfaces()取到的Type[]數組元素個數為0,上面的函數執行將會拋出異常
?? 經改造,正確的函數如下:
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() :返回表示當前Class 所表示的實體(類、接口、基本類型或 void)的直接超類的Type
最后總結一下:
對于實現接口而來的對象,使用getGenericInterfaces()與getActualTypeArguments()
對于繼承父類而來的對象,使用getGenericSuperclass()與getActualTypeArguments()