Java的泛型是假泛型,即只在编译期有效,在编译过程中会被“擦除”,也就是说,在运行期,JVM是无法推断泛型所代表的具体类型的,但这并不意味着我们无法获取编译好的Class的泛型信息。事实上,从JDK 1.5开始,Class的字节码中类、方法表、字段表的Signature属性会记录有关泛型的信息,我们可以通过相关反射API获取。
测试环境
Windows 10
Oracle JDK 8u241
相关知识
下面先介绍几个使用到的类和方法。
Type 接口
根据文档的描述
Type is the common superinterface for all types in the Java programming language. These include raw types, parameterized types, array types, type variables and primitive types."
翻译过来就是
Type 是 Java 语言中所有类型的接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。
具体来说 Class 类实现了这个接口,在Java SE API中,GenericArrayType, ParameterizedType, TypeVariable, WildcardType 是 Type 的子接口,因为 Class 是不包含参数化对象的泛型信息,所以就有了后面的几个接口,下面以含参字段为例我们一一介绍。
Field.getGenericType()
返回一个 Type 对象,它表示此 Field 对象所表示字段的声明类型。 如果类型不含参数,会直接返回 Class, 如果类型包含参数,那么返回包含源码中泛型的 Type。具体见以下例子。
GenericArrayType
若字段是泛型数组。
public class GenericArray<T> {
public T[] array;
public static void main(String[] args) throws Exception {
Field field = GenericArray.class.getField("array");
GenericArrayType type = (GenericArrayType) field.getGenericType(); // T[];
Type component = type.getGenericComponentType(); // T
}
}
ParameterizedType
若字段的参数无通配符"?"。
public class Parameterized {
public Map<String, Object> map;
public static void main(String[] args) throws Exception {
Field field = Parameterized.class.getField("map");
ParameterizedType type = (ParameterizedType) field.getGenericType();
Type rawType = type.getRawType(); // Map
Type key = type.getActualTypeArguments()[0]; // String
Type value = type.getActualTypeArguments()[1]; // Object
}
}
TypeVariable
若字段本身类型是参数。
public class Variable<T extends Number> {
public T number;
public static void main(String[] args) throws Exception {
Field field = Variable.class.getField("number");
TypeVariable<?> type = (TypeVariable<?>) field.getGenericType(); // Number
Type[] bounds = type.getBounds();
GenericDeclaration declare = type.getGenericDeclaration(); //Variable
}
}
WildCardType
若字段参数包含通配符“?”。
public class Wildcard {
public Function<? super Number, ? extends Number> func;
public static void main(String[] args) throws Exception {
Field field = Wildcard.class.getField("func");
ParameterizedType type = (ParameterizedType) field.getGenericType();
WildcardType in = (WildcardType) type.getActualTypeArguments()[0];
WildcardType out = (WildcardType) type.getActualTypeArguments()[0];
in.getLowerBounds(); // Number
in.getUpperBounds(); // Object
out.getLowerBounds(); // Object
out.getUpperBounds(); // Number
}
}
一个参数
字段
List listRawType;
List<String> listString;
Map mapRawType;
Map<String, Object> mapString2Object;