泛型,TypeToken(Guava)

众所周知,Java的泛型在运行时会有类型擦除。Guava的TypeToken却很好解决了这个问题。原因在匿名类+反射,其方法getSuperclassTypeParameter获取了Type。其中关键代码是调用了反射方法:

static Type getSuperclassTypeParameter(Class subclass) {
    // 获取泛型超类
    Type superclass = subclass.getGenericSuperclass();
    if (superclass instanceof Class) {
      throw new RuntimeException("Missing type parameter.");
    }
    // 类型参数,这个就是被擦除的泛型类型
    ParameterizedType parameterized = (ParameterizedType) superclass;
    return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
 }

其原理就是用一个继承TypeToken的匿名类,从而获取该匿名类的泛型超类,然后将其强制转换为ParameterizedTypeParameterizedType包含了其原始类型ParameterizedType.getRawType()及其泛型类型ParameterizedType.getActualTypeArguments()。举例:
对于List这个类,

List list = new ArrayList(){};
Type superclass = list.getClass().getGenericSuperclass();
ParameterizedType parameterized = (ParameterizedType) superclass;
Type raw = parameterized.getRawType();  // ArrayList类
Type[] types = parameterized.getActualTypeArguments();  // String类

如果是List>这种嵌套的泛型,那么还可以对上面Type[] types内的Type继续强制类型转换为ParameterizedType,嵌套获取其内嵌套的泛型。
注意

List list = new ArrayList(){};  //这是匿名类
不要写成
List list = new ArrayList(){}; 
或
List list = new ArrayList();  //这样不是继承,无法获取泛型

TypeLiteral可以通过TypeLiteral.getType()转换为Type,以便gson反序列化。也可以用比较原始的方式:

    // 改造自 TypeToken.getSuperclassTypeParameter()
    static Type getSuperclassTypeParameter(Class subclass) {
        Type superclass = subclass.getGenericSuperclass();
        if (superclass instanceof Class) {
            throw new RuntimeException("Missing type parameter.");
        }
        ParameterizedType parameterized = (ParameterizedType) superclass;
        return parameterized.getActualTypeArguments()[0];
    }

TypeLiteral typeLiteral = new TypeLiteral>() {};
Type type = getSuperclassTypeParameter(typeLiteral.getClass());
// gson反序列化
List list = gson.fromJson(json, type);  

你可能感兴趣的:(泛型,TypeToken(Guava))