静态泛型 与 运行时泛型
static class Demo<T> {
public T filedA;
public List<String> filedB;
}
Demo<String> stringDemo = new Demo<>();
Field filedA = stringDemo.getClass().getField("filedA");
System.out.println(filedA.getGenericType().getTypeName()); // T
Field filedB = stringDemo.getClass().getField("filedB");
System.out.println(filedB.getGenericType().getTypeName()); // java.util.List<java.lang.String>
我们会发现,fieldA
的泛型类型是获取不到的。为什么呢?
java
中的泛型会被编译器在编译时进行擦除,比如fieldA
实际上会被编译器转为Object
类型。List<String>
会被编译器擦除为List
,可以添加Object
类型的值。
不同点来了:fieldB
的泛型类型是在编译前就声明好的,是属于静态性质的。而fieldA
的泛型类型只有在运行时才能确定,属于运行时性质的,所以,fieldB
的泛型信息会被保存到即将要生成的Class
对象中。这样就解释了为什么可以通过反射获取到filedB
的泛型类型,但是fieldA
获取的为T
。
获取类的泛型类型
static class Demo<T> {
public T filedA;
}
static class Demo<String> {
public T filedA; // Failed to compile
}
结合上面提到的运行时泛型
可以发现:获取类自身的泛型类型是没有意义的
,因为静态编写类的泛型无意义,而通过泛型符设定的泛型运行时通过反射又获取不到(反射中甚至都没有关于获取类自身泛型的API,但是有获取父类泛型的。为什么?下面会有解释)。
那么当遇到下面的场景时,该如何获取呢?
Demo<String> stringDemo = new Demo<>();
// 获取 Demo 类的泛型 String
// stringDemo.getClass().get...
子类继承的方式
// 匿名内部类的方式继承Demo类
Demo<String> stringDemo = new Demo<String>() {};
// 获取父类的泛型类型
Type genericSuperclass = stringDemo.getClass().getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
// 打印泛型的实际类型的全限定名
for (Type actualTypeArgument : parameterizedType.getActualTypeArguments()) {
System.out.println(actualTypeArgument.getTypeName()); // java.lang.String
}
}
我们通过子类继承的形式,静态编写父类的泛型类型,这样就可以获取到了。
为什么反射中仅提供了获取父类泛型的API呢?很好理解,因为静态编写的父类泛型
是有意义的,因为会实际影响到父类中的内容。相对的,编写自身的静态泛型
是无意义的,什么都影响不到。但还是要注意下面这种形式:
static class BaseTest<T> {
}
static class Test<T> extends BaseTest<T> {
}
这样的结构依旧获取不到泛型类型,本质原因还是因为这是非静态编写的泛型
。
子类继承的方式 在开源库中的应用
String json = "...";
// fastjson 反序列化
TypeReference<Demo<String>> typeReference = new TypeReference<Demo<String>>() {};
Demo<String> fastJsonDemo = JSON.parseObject(json, typeReference);
// gson 反序列化
Type type = new TypeToken<Demo<String>>() {}.getType();
Demo<String> gsonDemo = new Gson().fromJson(json, type);
内部获取泛型类型正如我们上面的测试代码,以fastjson
为例:
public class TypeReference<T> {
private final Type type;
protected TypeReference(){
Type superClass = getClass().getGenericSuperclass();
type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public Type getType() {
return type;
}
public final static Type LIST_STRING = new TypeReference<List<String>>() {}.getType();
}