@edwin 的回答是正确的,你有一个XY Problem,你实际上是在要求错误的东西。值得庆幸的是,您在执行此操作时遇到了错误,导致您来到这里,@edwin 能够解释执行正确行为的替代方案。
Java 的每个绑定库都有一些类似的相同模式(Class 与类型引用)。所以这是在你的库中学习和寻找的好东西,比如 RestTemplate、Jackson、GSON 等。实用程序类可能是 ParameterizedTypeReference 在一个,TypeReference 在另一个,TypeRef 在另一个等等;但所有人都在做同样的事情。
现在,对于任何想知道原始代码有什么问题的人,要创建一个泛型擦除类引用,例如Class<T>,语法如下:
val ref = List::class.java
您会注意到无法表示列表中项目的通用类型。即使可以,由于类型擦除,它们无论如何都会被擦除。将此传递给绑定库就像说“请列出可能为空的 java.lang.Object 的列表”,但更糟。想象一下Map<String, List<Int>>,您现在丢失了所有使反序列化成为可能的信息。
以下无法编译:
val ref = List<String>::class.java // <--- error only classes are allowed on left side
错误消息可以更清楚地说“在 :: 的左侧只允许没有泛型参数的类”
而您对javaClass 的使用只能在一个实例上使用,所以如果您手头有一个列表...
val ref = listOf("one", "two", "three").javaClass
那么你最终会得到一个类型被删除的Class<T>,这也是在这里使用的错误,但语法有效。
那么@edwin 显示的代码实际上做了什么?
通过创建具有超类型ParameterizedTypeReference 的对象,代码可以解决这个问题,因为任何类,即使类型被删除,也可以通过Type 的镜头看到其超类和接口中的泛型。例如:
val xyz = object : MySuperClass<SomeGenerics>() {}
这个匿名类的实例具有超类MySuperClass,泛型参数为SomeGenerics。因此,如果MySuperClass 包含此代码:
abstract class MySuperClass<T> protected constructor() {
val type: Type = (javaClass.genericSuperclass as ParameterizedType)
.actualTypeArguments[0]
}
然后您可以将.type 添加到我们声明的末尾以访问此功能:
val typeOfSomeGenerics = object : MySuperClass<SomeGenerics>() {}.type
现在你会有一些Type 的实现来描述我们的SomeGenerics 类。它将是以下之一:Class、ParameterizedType、GenericArrayType、TypeVariable 和 WildcardType
通过理解和使用这些,进行数据绑定的库知道足以完成其工作。
在 Kotlin 中生活更轻松:
在 Kotlin 中,编写扩展函数很容易,这样您就不必多次编写此类代码。只需创建一个辅助内联函数,该函数使用具体化的泛型来传递类型并创建ParameterizedTypeReference:
inline fun <reified T: Any> typeRef(): ParameterizedTypeReference<T> = object: ParameterizedTypeReference<T>(){}
现在您可以将@edwin 的示例更改为:
val response = restTemplate.exchange(request, typeRef<List<String>>())