1 核心接口及类
fastJson 的泛型反序列化场景经常使用到 TypeReference,如下示例:
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构造器
ParameterizedType是一个记录类型泛型的接口, 继承自Type, 一共三接口
- Type[] getActualTypeArguments 核心接口,返回泛型类型数组, 该接口可获取父类实际泛型类型,返回的Type数组对象表示该类型的实际类型参数。
- Type getRawType() 返回原始类型Type
-
Type getOwnerType()
返回 Type 对象,表示此类型是其成员之一的类型。
比如Map响应ParameterizedType三个接口的返回值如下:
- [class java.lang.String, class java.lang.String]
- interface java.util.Map
- null
一般使用如下
new TypeReference<List<String>>(){}
创建一个TypeReference的匿名类,在其构造器中拿到泛型对应Type(java.lang.reflect.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====="); 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> { } }
输出为
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
获取到了实际类型,就可实现对泛型的反序列化。
Java虽然运行时会有类型擦除,但会保留Field的泛型信息,可通过Field.getGenericType()取字段的泛型。
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()); } }
输出
=====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来获取
Object mapVal = map.get(kest); if(mapVal != null){ Class<?> clz = mapVal.getClass(); System.out.println(mapVal.getClass().getName()); }
因为泛型的运行时擦除,对于局部变量来说, 泛型信息是无法获取的
参考
- http://www.java2s.com/Tutorials/Java/java.lang/Class/Java_Class_getGenericSuperclass_.htm
- https://zhaoyanblog.com/archives/186.html
- https://developer.aliyun.com/article/609441