为什么不能按需要使用TypeToken?

时间:2019-06-07 07:54:11

标签: java android oop generics gson

我正在尝试解决反序列化HashMap<Integer, MyParcelablePojo>时遇到的问题。为了找到答案,我发现了以下问题:

如果我尝试:

HashMap<Integer, MyParcelablePojo> mHashMap = new Gson().fromJson(the_json_string, HashMap.class);

...生成的HashMap包含LinkedTreeMap个对象,而不是MyParcelablePojo个对象。

由于这个原因,我试图以与上面第二个问题类似的方式使用TypeToken,但是它不允许我指定HashMap的参数。如果我尝试:

// XXX I am not sure if this "Type" is the correct one
//     there were several "Type" classes to choose from
import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;

Type collection_type = new TypeToken<HashMap<Integer, MyParcelablePojo>>();

... Android Studio向我显示此错误:

  

'TypeToken()'已保护'com.google.gson.reflect.TypeToken'中的访问权限

...只是为了坚持我所看到的示例,我尝试使用new TypeToken<HashMap<T>>来查看错误是否消失了(出于好奇,我对此不感兴趣使用通用T全部),然后说“无法解析T”,这太奇怪了……但这与我的问题无关,我只是为了完整起见才添加了它……

... 回到重点,所以TypeToken的构造函数受到保护,对吗?因此,扩展课程可能会有帮助,对吗?但是,如果我看到了构造函数,对我来说太奇怪了。参数化类型非常奇怪地使用这种方式(至少就我目前对它们的理解而言)。 <? super T>部分有点令人困惑(看起来它正在调用T的父类型,但我只是没有完全理解它)。但是,对我来说更奇怪的是$Gson$Types.getRawType(type) ...我想知道$用于...的那些是什么:

protected TypeToken() {
    this.type = getSuperclassTypeParameter(getClass());
    this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);
    this.hashCode = type.hashCode();
}

直奔主题

我只想避免Gson.fromJson方法返回LinkedTreeMap而不是MyParcelablePojo作为值。链接的问题中提供的答案对我来说似乎太笼统了,所以我不知道如何将其应用于我的案例(请注意,我暂时不对笼统性感兴趣)。我什至怀疑它们是否适用于我的情况。

我使用HashMap的主要动机是因为我想使用ID基础自己定义索引。我应该怎么做才能正确解决从JSON字符串反序列化的问题?

3 个答案:

答案 0 :(得分:2)

您通过创建通常是匿名的子类来实例化TypeToken

Type collection_type = new TypeToken<HashMap<Integer, MyParcelablePojo>>(){}.getType();

请注意我的答案中的{}。其原因在JavaDoc中进行了解释:

/**
 * Represents a generic type {@code T}. Java doesn't yet provide a way to
 * represent generic types, so this class does. Forces clients to create a
 * subclass of this class which enables retrieval the type information even at
 * runtime.
 *
 * <p>For example, to create a type literal for {@code List<String>}, you can
 * create an empty anonymous inner class:
 *
 * <p>
 * {@code TypeToken<List<String>> list = new TypeToken<List<String>>() {};}
 *
 * <p>This syntax cannot be used to create type literals that have wildcard
 * parameters, such as {@code Class<?>} or {@code List<? extends CharSequence>}.
 *
 * @author Bob Lee
 * @author Sven Mawson
 * @author Jesse Wilson
 */

答案 1 :(得分:2)

如果您正在使用Kotlin,请不要忘记使用 object:

val type: Type = object : TypeToken<ArrayList<YourArrayType>>() {}.type

答案 2 :(得分:1)

我认为您没有正确使用TypeToken,

HashMap<Integer, GenericObject> mHashMap = new Gson().fromJson(json, new TypeToken<HashMap<Integer, GenericObject>>(){}.getType());

在传递类型的地方,而不是实际的令牌。