Gson解析泛型中的类型擦除问题

2,108 阅读1分钟

问题

在Gson中可以使用TypeToken来支持List< >的泛型解析。

Type type = new TypeToken<List<xxx>>(){}.getType();
T result = new Gson().fromJson(str, type);

为了在api接口中限制返回的解析结果,并且为了简化代码只希望在方法参数上指定一次具体解析类,尝试对Gson解析过程进行以下封装。

Type type = new TypeToken<T>(){}.getType();
T result = new Gson().fromJson(str, type);

发现result被解析为com.google.gson.internal.LinkedTreeMap, 而不是使用时指定的List< >,分析后发现是java中的类型擦除导致的。

类型擦除

在编译期间检测到泛型的具体使用,并自动生成对应的具体实现。 因此只能在具体调用时去指定类型。

  1. 将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
  2. 移除所有的类型参数。

相关介绍 blog.csdn.net/gstormspire…

  • 不能用同一泛型类的实例区分方法签名
  • 泛型类的静态变量是共享的

解决方案

//stringCallback指定了调用时的具体泛型,如:CallBack<List<Data>>最终返回的Type是List<Data>

static Type getType(@NonNull ApiCallBack stringCallback){
        //返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type。
        Type genericSuperclass = stringCallback.getClass().getGenericSuperclass();
        ParameterizedType types = (ParameterizedType) genericSuperclass;
     
        if(types == null){
            throw new IllegalStateException("泛型获取异常");
        }
        
        Type typeArgument;
        try{
            Type[] actualTypeArguments = types.getActualTypeArguments();
            typeArgument = actualTypeArguments[0];
            //返回表示此类型实际类型参数的 Type 对象的数组(),想要获取第一个泛型的Class,所以索引写0
        }catch (Exception e){
            throw new IllegalStateException("泛型获取异常");
        }
        return typeArgument;
    }