如何在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”。