如何在Kotlin中使用Gson的TypeToken +泛型
我无法从自定义类(Turns)中获取泛型类型的列表:
val turnsType = TypeToken<List<Turns>>() {}.type val turns = Gson().fromJson(pref.turns, turnsType)
它说:
cannot access '<init>' it is 'public /*package*/' in 'TypeToken'
创建这个内联的乐趣:
inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
然后你可以这样调用它:
val turns = Gson().fromJson<Turns>(pref.turns) // or val turns: Turns = Gson().fromJson(pref.turns)
注意 :这种方法在旧的kotlin插件版本中是不可能的,但是现在您可以使用它了。
以前的替代方案:
备选1:
val turnsType = object : TypeToken<List<Turns>>() {}.type val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)
你必须把object :
和来自fromJson<List<Turns>>
的具体类型
备选2:
正如@cypressious提到的那样,也可以这样来实现:
inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
用于:
val turnsType = genericType<List<Turns>>()
这解决了这个问题:
val turnsType = object : TypeToken<List<Turns>>() {}.type val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)
第一行创建一个从TypeToken
的对象表达式 ,然后从中获取Java Type
。 然后Gson().fromJson
方法或者需要为函数结果指定的类型(它应该与创建的TypeToken
匹配)。 这个工作的两个版本,如上所述或者:
val turns: List<Turns> = Gson().fromJson(pref.turns, turnsType)
为了方便创建TypeToken
,可以创建一个辅助函数,该函数需要内联才能使用实体类型参数 :
inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
然后可以用以下任何一种方式使用:
val turnsType = genericType<List<Turns>>() // or val turnsType: List<Turns> = genericType()
整个过程可以被包装成一个Gson
实例的扩展函数:
inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
所以你可以直接调用Gson而不用担心TypeToken
:
val turns = Gson().fromJson<Turns>(pref.turns) // or val turns: Turns = Gson().fromJson(pref.turns)
这里Kotlin使用类型推断从赋值的一边或另一边,为内联函数的泛化泛型通过完整类型(不擦除),并使用它来构造一个TypeToken
并且调用Gson
这也适用,而且更简单
inline fun <reified T> Gson.fromJson(json: String) : T = this.fromJson<T>(json, T::class.java)
另一种选择(不知道它看起来比其他人更优雅)可能是这样的一个电话:
turns = Gson().fromJson<Array<Turns>>(allPurchasesString, Array<Turns>::class.java).toMutableList()
所以你正在使用Java Array类的班轮,而不是“纯Kotlin”。