要获得要用于json反序列化的类定义,可以在Kotlin中使用以下内容:
Map::class.java
示例用法如下:
val map = mapper.readValue(json, Map::class.java)
但是现在如何进行泛型类型定义呢?
像这样的东西不会编译:
val map = mapper.readValue(decodedString, Map<String, String>::class.java)
所以我的问题是:*::class.java
的通用等价物是什么
Class<T>
(在Java中)或KClass<T>
(在Kotlin中)只能表示类,而不能表示所有类型。如果您使用的API只使用Class<T>
或KClass<T>
,那么它根本不支持泛型类型(至少在这些函数中)。
相反,KType(或Java中的Type
)是用来表示包括泛型在内的完整类型信息的合适类型。你可以这样使用它:
val myMapType: KType = typeOf<Map<String,String>>()
不幸的是,KType
没有类型参数(它不是KType<T>
),这使得它无法用于编译时类型检查:您不能使用KType
而不是KClass
来获得等效的fun deserialize(Input, KClass<T>): T
,因为您不能仅使用KType
参数来定义返回类型的T
。
有几个技巧可以解决这个问题:
在Java和Kotlin中,其中一种方法是通过提供泛型超类并从中继承来通过继承来获得这些信息。
一般来说,序列化API(尤其是反序列化部分)提供了使用它的变通方法,例如Jackson的TypeReference或Gson的TypeToken。它基本上是他们的
Type
版本,但有一个类型参数,以确保编译时的类型安全。在Kotlin中,有时根据情况还有另一种方法:使用具体化的类型参数。使用内联函数,编译器可以在编译时了解有关类型参数的更多信息,方法是在内联函数体时,在调用位置将它们替换为实际推断的类型。这允许在内联函数的主体中使用
T::class
之类的内容。这就是如何获得typeOf这样的函数来获得KType
。一些特定于Kotlin的反序列化库API使用内联函数来消除用户的麻烦,并直接获取类型信息。这就是jackson模块kotlin所做的,它提供了一个没有
Class
参数的内联readValue
扩展,它具体化了类型参数以获得目标类型信息