博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
为什么使用TypeReference
阅读量:6701 次
发布时间:2019-06-25

本文共 4570 字,大约阅读时间需要 15 分钟。

在使用fastJson的时候对于泛型的反序列化很多场景下都会使用到TypeReference,例如:

public static void main(String[] args) {        List
list = 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, 一共三方法:

  • 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中子类可以获取到父类泛型的真实类型,为了便于理解,看一段测试代码

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
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
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() 取字段的泛型。
exp

public class FieldGenericKest {    public  Map
map = 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

但是注意,这里不能获取到字段的真实类型HashMapArrayList

真实的类型当然不能用Field来获取,需要用对应的Value来获取

Object mapVal = map.get(kest);if(mapVal != null){    Class
clz = mapVal.getClass(); System.out.println(mapVal.getClass().getName());}

pps.

因为泛型的运行时擦除,对于局部变量来说, 泛型信息是无法获取的

转载地址:http://ylwlo.baihongyu.com/

你可能感兴趣的文章
前端学习资源
查看>>
FPGA算法映射要点
查看>>
带你玩转 JavaScript ES6 (六) - Map 映射
查看>>
【313天】我爱刷题系列072(2017.12.15)
查看>>
Android简易柱状图和曲线图表实现
查看>>
android新技术
查看>>
div宽度和高度固定,让图片铺满整个div而且不变形
查看>>
逆向- 拉好友进行群
查看>>
JavaScript的作用域、闭包、(apply, call, bind)
查看>>
React.js 小书 Lesson23 - dangerouslySetHTML 和 style 属性
查看>>
vscode调试node
查看>>
【290天】每日项目总结系列028(2017.11.22)
查看>>
JDK1.8 ArrayList部分源码分析小记
查看>>
R语言机器学习框架h2o基础学习教程
查看>>
java9系列(二)docker运行java9
查看>>
JSON的理解
查看>>
LeetCode: Binary Tree Maximum Path Sum
查看>>
1.平凡之路-ORM概述
查看>>
Electron(1.6.11) + koa2 仿腾讯TGP游戏登录器(一):环境部署
查看>>
es8的字符串填充、关于对象、关于函数
查看>>