本文共 4570 字,大约阅读时间需要 15 分钟。
在使用fastJson的时候对于泛型的反序列化很多场景下都会使用到TypeReference,例如:
public static void main(String[] args) { Listlist = new ArrayList (); list.add("1"); list.add("2"); JSONObject o = new JSONObject(); o.put("k",list); List types = o.getObject("k",List.class); System.out.println(JSON.toJSONString(types)); List types2 = o.getObject("k",new TypeReference
>(){}); System.out.println(JSON.toJSONString(types2)); }
使用TypeReference可以明确的指定反序列化的类型,具体实现逻辑参考TypeReference的构造函数
protected TypeReference(){ Type superClass = getClass().getGenericSuperclass(); Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0]; Type cachedType = classTypeCache.get(type); if (cachedType == null) { classTypeCache.putIfAbsent(type, type); cachedType = classTypeCache.get(type); } this.type = cachedType; }
核心的方法是getActualTypeArguments
,此方法可以获取父类真实的泛型类型。具体参考注释java.lang.Class#getGenericSuperclass
。
new TypeReference<List<String>>(){}
创建了一个继承TypeReference>的匿名子类,在其构造函数中拿到了泛型对应Type(java.lang.reflect.ParameterizedType
)。 ParameterizedType是一个记录类型泛型的接口, 继承自Type, 一共三方法:
例如 Map<String,String>
对应的ParameterizedType三个方法分别取值如下:
TypeReference
的存在是因为java中子类可以获取到父类泛型的真实类型,为了便于理解,看一段测试代码
public class TypeReferenceKest { public static void main(String[] args) { IntMap intMap = new IntMap(); System.out.println(intMap.getClass().getSuperclass()); Type type = intMap.getClass().getGenericSuperclass(); if(type instanceof ParameterizedType){ ParameterizedType p = (ParameterizedType) type; for (Type t : p.getActualTypeArguments()){ System.out.println(t); } } System.out.println("=====newclass====="); HashMapnewIntMap = new HashMap<>(); System.out.println(newIntMap.getClass().getSuperclass()); Type newClassType = newIntMap.getClass().getGenericSuperclass(); if(newClassType instanceof ParameterizedType){ ParameterizedType p = (ParameterizedType) newClassType; for (Type t : p.getActualTypeArguments()){ System.out.println(t); } } System.out.println("=====subclass====="); HashMap subIntMap = new HashMap (){}; System.out.println(subIntMap.getClass().getSuperclass()); Type subClassType = subIntMap.getClass().getGenericSuperclass(); if(subClassType instanceof ParameterizedType){ ParameterizedType p = (ParameterizedType) subClassType; for (Type t : p.getActualTypeArguments()){ System.out.println(t); } } } public static class IntMap extends HashMap { }}
输出为
class java.util.HashMapclass java.lang.Stringclass java.lang.Integer=====newclass=====class java.util.AbstractMapKV=====subclass=====class java.util.HashMapclass java.lang.Stringclass java.lang.Integer
获取到了真实的类型,就可以实现对泛型的反序列化了。
参考资料
ps.
java虽然运行时会有类型擦除,但是会保留Field的泛型信息,可以通过Field.getGenericType() 取字段的泛型。exppublic class FieldGenericKest { public Mapmap = new HashMap<>(); public List list = new ArrayList<>(); public static void main(String[] args) throws Exception { FieldGenericKest kest = new FieldGenericKest(); Field map = kest.getClass().getField("map"); Field list = kest.getClass().getField("list"); System.out.println("=====map====="); System.out.println("map.getType=" + map.getType()); System.out.println("map.getGenericType=" + map.getGenericType()); System.out.println("=====list====="); System.out.println("list.getType=" + list.getType()); System.out.println("list.getGenericType=" + list.getGenericType()); }}
输出
=====map=====map.getType=interface java.util.Mapmap.getGenericType=java.util.Map=====list=====list.getType=interface java.util.Listlist.getGenericType=java.util.List
但是注意,这里不能获取到字段的真实类型HashMap
和ArrayList
。
Object mapVal = map.get(kest);if(mapVal != null){ Class clz = mapVal.getClass(); System.out.println(mapVal.getClass().getName());}
pps.
因为泛型的运行时擦除,对于局部变量来说, 泛型信息是无法获取的转载地址:http://ylwlo.baihongyu.com/