如題,有時候我們在接口中或者是抽象類使用泛型來適應子類不同的類型,可是當我們需要拿到泛型實例或者泛型類型的時候,可以這樣去得到:
抽象類和接口各不相同。
- 抽象類獲取泛型實例的方法
Class<?> aClass = obj.getClass();//先得到類的字節碼
Type genericSuperclass = aClass.getGenericSuperclass();// 返回超類的type
ParameterizedType types = (ParameterizedType) genericSuperclass;// 如果超類是參數化類型,返回的Type對象必須準確地反映源代碼中使用的實際類型參數,也就是 ParameterizedType 類型
Type[] actualTypeArguments = types.getActualTypeArguments();//返回表示此類型的實際類型參數的Type對象的數組。請注意,在某些情況下,返回的數組是空的。如果此類型表示嵌套在參數化類型中的非參數化類型,則會發生這種情況。
Class<T> reponseClass = (Class) actualTypeArguments[0];
- 接口獲取泛型實例的方法
Class<?> aClass = obj.getClass();//先得到類的字節碼
/*
返回表示由此對象表示的類或接口直接實現的接口的類型。
如果超級接口是一個參數化類型,返回的Type對象必須準確地反映源代碼中使用的實際類型參數。代表每個超級界面的參數化類型是在之前沒有創建的情況下創建的。有關參數化類型的創建過程的語義,請參閱ParameterizedType的聲明。
如果此對象表示一個類,則返回值是一個包含表示由類實現的所有接口的對象的數組。數組中接口對象的順序對應于該對象表示的類的聲明的implements子句中的接口名稱的順序。在數組類中,接口Cloneable和Serializable按照這個順序返回。
如果此對象表示一個接口,則該數組包含表示由該接口直接擴展的所有接口的對象。數組中接口對象的順序對應于該對象表示的接口聲明的extends子句中接口名稱的順序。
如果此對象表示不實現接口的類或接口,則該方法返回長度為0的數組。
如果這個對象表示一個原始類型或void,則該方法返回一個長度為0的數組。
* */
Type[] types = aClass.getGenericInterfaces();
ParameterizedType parameterizedType = (ParameterizedType) types[0];
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
Class<T> reponseClass = (Class) actualTypeArguments[0];
最后附上完整工具類代碼:
/**
* 運行時獲取泛型類型
*/
public class GenericUtil {
public static <T> T getSuperclassType(Object obj, int i) {
try {
Class<?> aClass = obj.getClass();//先得到類的字節碼
Type genericSuperclass = aClass.getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
ParameterizedType types = (ParameterizedType) genericSuperclass;//抽象類
Type[] actualTypeArguments = types.getActualTypeArguments();
Class<T> reponseClass = (Class) actualTypeArguments[i];
return reponseClass.newInstance();
} else {
return null;
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public static <T> T getInterfaceType(Object obj, int i) {
try {
Class<?> aClass = obj.getClass();//先得到類的字節碼
/*
返回表示由此對象表示的類或接口直接實現的接口的類型。
如果超級接口是一個參數化類型,返回的Type對象必須準確地反映源代碼中使用的實際類型參數。代表每個超級界面的參數化類型是在之前沒有創建的情況下創建的。有關參數化類型的創建過程的語義,請參閱ParameterizedType的聲明。
如果此對象表示一個類,則返回值是一個包含表示由類實現的所有接口的對象的數組。數組中接口對象的順序對應于該對象表示的類的聲明的implements子句中的接口名稱的順序。在數組類中,接口Cloneable和Serializable按照這個順序返回。
如果此對象表示一個接口,則該數組包含表示由該接口直接擴展的所有接口的對象。數組中接口對象的順序對應于該對象表示的接口聲明的extends子句中接口名稱的順序。
如果此對象表示不實現接口的類或接口,則該方法返回長度為0的數組。
如果這個對象表示一個原始類型或void,則該方法返回一個長度為0的數組。
* */
Type[] types = aClass.getGenericInterfaces();
ParameterizedType parameterizedType = (ParameterizedType) types[0];
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
Class<T> reponseClass = (Class) actualTypeArguments[i];
return reponseClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public static Class<?> forName(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}