众所周知,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
的匿名类,从而获取该匿名类的泛型超类,然后将其强制转换为ParameterizedType
。ParameterizedType
包含了其原始类型ParameterizedType.getRawType()
及其泛型类型ParameterizedType.getActualTypeArguments()
。举例:
对于List<String>
这个类,
List list = new ArrayList<String>(){};
Type superclass = list.getClass().getGenericSuperclass();
ParameterizedType parameterized = (ParameterizedType) superclass;
Type raw = parameterized.getRawType(); // ArrayList类
Type[] types = parameterized.getActualTypeArguments(); // String类
如果是List<List<String>>
这种嵌套的泛型,那么还可以对上面Type[] types
内的Type
继续强制类型转换为ParameterizedType
,嵌套获取其内嵌套的泛型。
注意
List list = new ArrayList<String>(){}; //这是匿名类
不要写成
List<String> list = new ArrayList(){};
或
List list = new ArrayList<String>(); //这样不是继承,无法获取泛型
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<List<String>>() {};
Type type = getSuperclassTypeParameter(typeLiteral.getClass());
// gson反序列化
List<String> list = gson.fromJson(json, type);
网友评论