如题,有时候我们在接口中或者是抽象类使用泛型来适应子类不同的类型,可是当我们需要拿到泛型实例或者泛型类型的时候,可以这样去得到:
抽象类和接口各不相同。
- 抽象类获取泛型实例的方法
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;
}
}