TypeReference的作用
在使用fastJson的时候对于泛型的反序列化很多场景下都会使用到TypeReference,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static void main (String[] args) { List<String> list = new ArrayList <String>(); list.add("1" ); list.add("2" ); JSONObject o = new JSONObject (); o.put("k" ,list); List<String> types = o.getObject("k" ,List.class); System.out.println(JSON.toJSONString(types)); List<String> types2 = o.getObject("k" ,new TypeReference <List<String>>(){}); System.out.println(JSON.toJSONString(types2)); }
使用TypeReference可以明确的指定反序列化的类型,具体实现逻辑参考TypeReference的构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 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<List>的匿名子类,在其构造函数中拿到了泛型对应Type(java.lang.reflect.ParameterizedType)。
ParameterizedType是一个记录类型泛型的接口, 继承自Type, 一共三方法:
Type[] getActualTypeArguments(); //返回泛型类型数组
Type getRawType(); //返回原始类型Type
Type getOwnerType(); //返回 Type 对象,表示此类型是其成员之一的类型。
例如 Map<String,String> 对应的ParameterizedType三个方法分别取值如下:
[class java.lang.String, class java.lang.String]
interface java.util.Map
null
TypeReference的存在是因为java中子类可以获取到父类泛型的真实类型,为了便于理解,看一段测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 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=====" ); HashMap<String,Integer> newIntMap = 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<String,Integer> subIntMap = new HashMap <String,Integer>(){}; 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 <String,Integer> { } }
输出为
1 2 3 4 5 6 7 8 9 10 11 12 class java.util.HashMap class java.lang.String class java.lang.Integer =====newclass===== class java.util.AbstractMap K V =====subclass===== class java.util.HashMap class java.lang.String class java.lang.Integer
获取到了真实的类型,就可以实现对泛型的反序列化了。
参考资料
http://www.java2s.com/Tutorials/Java/java.lang/Class/Java_Class_getGenericSuperclass_.htm
https://zhaoyanblog.com/archives/186.html
ps. java虽然运行时会有类型擦除,但是会保留Field的泛型信息,可以通过Field.getGenericType() 取字段的泛型。 exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class FieldGenericKest { public Map<String,Integer> map = new HashMap <>(); public List<Long> 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()); } }
输出
1 2 3 4 5 6 =====map===== map.getType=interface java.util.Map map.getGenericType=java.util.Map<java.lang.String, java.lang.Integer> =====list===== list.getType=interface java.util.List list.getGenericType=java.util.List<java.lang.Long>
但是注意,这里不能获取到字段的真实类型HashMap和ArrayList。 真实的类型当然不能用Field来获取,需要用对应的Value来获取
1 2 3 4 5 6 7 8 9 Object mapVal = map.get(kest);if (mapVal != null ){ Class<?> clz = mapVal.getClass(); for ( ;clz.isAnonymousClass();) { clz = clz.getSuperclass(); } java.lang.reflect.Type rawType = (java.lang.reflect.Type) clz; System.out.println(rawType.getTypeName()); }
pps.因为泛型的运行时擦除,对于局部变量来说, 泛型信息是无法获取的