首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >fastjson为何使用TypeReference?

fastjson为何使用TypeReference?

作者头像
JavaEdge
发布2021-02-23 11:57:01
发布2021-02-23 11:57:01
1.3K0
举报
文章被收录于专栏:JavaEdgeJavaEdge

1 核心接口及类

fastJson 的泛型反序列化场景经常使用到 TypeReference,如下示例:

代码语言:javascript
复制
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.1 ParameterizedType接口

ParameterizedType是一个记录类型泛型的接口, 继承自Type, 一共三接口

  1. Type[] getActualTypeArguments 核心接口,返回泛型类型数组, 该接口可获取父类实际泛型类型,返回的Type数组对象表示该类型的实际类型参数。
  2. Type getRawType() 返回原始类型Type
  3. Type getOwnerType() 返回 Type 对象,表示此类型是其成员之一的类型。

比如 Map 响应ParameterizedType三个接口的返回值如下:

  • [class java.lang.String, class java.lang.String]
  • interface java.util.Map
  • null

fastjson对其的实现类

一般使用如下

代码语言:javascript
复制
new TypeReference<List<String>>(){}

创建一个TypeReference的匿名类,在其构造器中拿到泛型对应Type(java.lang.reflect.ParameterizedType)

TypeReference的存在是因为java中子类可以获取到父类泛型的真实类型,为便于理解,看一段测试代码

代码语言:javascript
复制
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> {
    }
}

输出为

代码语言:javascript
复制
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() 取字段的泛型。

代码语言:javascript
复制
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());
    }
}

输出

代码语言:javascript
复制
=====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来获取

代码语言:javascript
复制
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
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/09/26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 核心接口及类
    • 1.1 ParameterizedType接口
    • fastjson对其的实现类
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档