我想像这样RestTemplate在Kotlin中使用Spring :
RestTemplate
//import org.springframework.web.client.RestTemplate fun findAllUsers(): List<User> { val restTemplate = RestTemplate() //has error val ret = List<User>.javaClass return restTemplate.getForObject(URI(hostAddress), ret) }
该RestTemplate.getForObject(URI url, Class<T> responseType)有这个签名,我从得到这个错误“未解决的参考序列” List在val ret = List<User>.javaClass。
RestTemplate.getForObject(URI url, Class<T> responseType)
List
val ret = List<User>.javaClass
如果我这样使用,val ret = List<User>::class.java则会出现此错误“类字面量的左侧仅允许类”
val ret = List<User>::class.java
有什么问题?这样做的正确方法是什么?是虫子吗?
@edwin的答案是正确的,您遇到了XY问题,您实际上是在问错了什么。值得庆幸的是,您在执行此操作时遇到了一个错误,这导致您进入此处,@ edwin能够解释执行正确行为的替代方法。
每个Java绑定库都具有类似的模式(Class与类型引用相对)。因此,这是好东西,您可以在您的库中学习和查找,例如RestTemplate,Jackson,GSON等。实用程序类可能ParameterizedTypeReference在一个中,TypeReference在另一个中,TypeRef在另一个中,依此类推;但所有人都在做同一件事。
Class
ParameterizedTypeReference
TypeReference
TypeRef
现在,对于任何想知道原始代码有什么问题的人 ,创建一个泛型擦除的类引用(例如Class<T>语法)将是:
Class<T>
val ref = List::class.java
您会注意到没有办法表达列表中项目的通用类型。即使可以,它们也会由于类型擦除而被擦除。将此传递给绑定库就像说“ 请为可能为空的java.lang.Object的列表 ”,但更糟。想象一下Map<String, List<Int>>,您现在在哪里丢失了所有可能反序列化的信息。
Map<String, List<Int>>
以下内容 无法 编译:
val ref = List<String>::class.java // <--- error only classes are allowed on left side
错误消息可能更清楚地说:“ ::左侧仅允许没有通用参数的类 ”
并且您javaClass只能在实例上使用,因此,如果您碰巧拥有一个方便的列表…
javaClass
val ref = listOf("one", "two", "three").javaClass
然后,您将得到一个擦除的类型Class<T>,这再次是在这里使用错误的东西,但语法正确。
那么@edwin显示的代码实际上是做什么的呢?
通过创建具有超类型ParameterizedTypeReference的对象,代码可以解决此问题,因为即使删除了类型,任何类都可以通过的镜头看到其超类和接口中的泛型Type。例如:
Type
val xyz = object : MySuperClass<SomeGenerics>() {}
匿名类的该实例具有MySuperClass具有通用参数的超类SomeGenerics。因此,如果MySuperClass包含以下代码:
MySuperClass
SomeGenerics
abstract class MySuperClass<T> protected constructor() { val type: Type = (javaClass.genericSuperclass as ParameterizedType) .actualTypeArguments[0] }
然后,您可以添加 .type到声明的末尾以访问此功能:
.type
val typeOfSomeGenerics = object : MySuperClass<SomeGenerics>() {}.type
现在,您将具有一些Type描述我们的SomeGenerics类的实现。这将是一个: Class,ParameterizedType,GenericArrayType,TypeVariable,和WildcardType
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>>())