如何在运行时(Runtime)获得泛型的真正类型
如何在运行时(Runtime)获得泛型的真正类型
前言
由于Java 的类型擦除机制,在编译时泛型都被转为了Object,例如List<String>
经过编译之后将变为类型 List。可以通过以下的方式再运行时获得泛型的真正类型
泛型如何获得具体类型
List 例子如下
来自:https://stackoverflow.com/questions/1942644/get-generic-type-of-java-util-list
package test;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
public class Test {
List<String> stringList = new ArrayList<String>();
List<Integer> integerList = new ArrayList<Integer>();
public static void main(String... args) throws Exception {
Field stringListField = Test.class.getDeclaredField("stringList");
ParameterizedType stringListType = (ParameterizedType) stringListField.getGenericType();
Class<?> stringListClass = (Class<?>) stringListType.getActualTypeArguments()[0];
System.out.println(stringListClass); // class java.lang.String.
Field integerListField = Test.class.getDeclaredField("integerList");
ParameterizedType integerListType = (ParameterizedType) integerListField.getGenericType();
Class<?> integerListClass = (Class<?>) integerListType.getActualTypeArguments()[0];
System.out.println(integerListClass); // class java.lang.Integer.
}
}
Map 的例子如下
来自:https://stackoverflow.com/questions/3687766/how-to-get-value-type-of-a-map-in-java
import java.lang.reflect.*;
import java.util.*;
public class Generic {
private Map<String, Number> map = new HashMap<String, Number>();
public static void main(String[] args) {
try {
ParameterizedType pt = (ParameterizedType)Generic.class.getDeclaredField("map").getGenericType();
for(Type type : pt.getActualTypeArguments()) {
System.out.println(type.toString());
}
} catch(NoSuchFieldException e) {
e.printStackTrace();
}
}
}
实际二者都利用的反射
jackson 中是如何实现的
jackson 中将JSON 转为Map 的可以通过如下代码实现,方式一:
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"mkyong\", \"age\":29}";
Map map = mapper.readValue(json, Map.class);
Object name = map.get("name")
上述只是指定了是 Map 类型,但是没有指定Map里边存放的数据是什么类型,所以得到结果之后还需要对 Object name
做一次强制类型转换才能够使用。
可以使用方式二,告知实际 Map
中存放的对象,从而得到正确的类型,代码如下所示:
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"mkyong\", \"age\":29}";
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, String>>(){});
TypeReference
实际上就是告诉了 ObjectMapper
反序列化时要转换的真正类型是什么。
TypeReference 源码
package com.fasterxml.jackson.core.type;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public abstract class TypeReference<T> implements Comparable<TypeReference<T>> {
protected final Type _type;
protected TypeReference() {
Type superClass = this.getClass().getGenericSuperclass();
if (superClass instanceof Class) {
throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
} else {
this._type = ((ParameterizedType)superClass).getActualTypeArguments()[0];
}
}
public Type getType() {
return this._type;
}
public int compareTo(TypeReference<T> o) {
return 0;
}
}
有一个 protected
的构造器,所以在使用的时候默认就会执行该构造器,上述方案二将会走到分支代码 this._type = ((ParameterizedType)superClass).getActualTypeArguments()[0];
,从而 getType
能够得到正确的类型。实际上也是根据 ParameterizedType
获得真正的类型。
通过 TypeReference 获得真正类型
代码类似如下,最后得到的 tmpType1
是 Class
类型,就能够基于它其他的操作了。
TypeReference<Map<String, Test>> typeReference = new TypeReference<Map<String, Test>>(){};
ParameterizedType type = (ParameterizedType)typeReference.getType();
for (Type tmpType : type.getActualTypeArguments()) {
Class<?> tmpType1 = (Class<?>) tmpType;
System.out.println(tmpType1);
}
欢迎转载,但请注明本文链接,谢谢你。
2018.10.28 20:47