Kotlin使用Class <T>参数调用java方法

我想要像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中获取这个错误“unresolved reference List” val ret = List<User>.javaClass

如果我使用像这样val ret = List<User>::class.java我得到这个错误“只允许在类类型左边的类”

有什么问题? 以及这样做的正确方法是什么? 这是一个错误?

@ edwin的答案是正确的,你有一个XY问题 ,你实际上是在问错误的东西。 谢天谢地,你这样做的错误导致你在这里,@edwin能够解释做出正确行为的替代方案。

Java的每个绑定库都有一些像这样的模式( Class与类型引用)。 所以这是学习和寻找你的图书馆,如RestTemplate,杰克逊,GSON和其他人的好东西。 实用程序类可以是ParameterizedTypeReference中的一个, TypeReference中的另一个, TypeRef中的另一个等等; 但都做同样的事情。

现在,对于想知道原始代码有什么问题的人来说 ,要创建泛型擦除类引用(如Class<T> ,语法是:

 val ref = List::class.java 

您会注意到无法表示列表中项目的通用类型。 而且,即使可以,由于类型删除,它们也会被删除。 把这个传递给绑定库就像是在说“ 可能为null的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类。 它将是以下类型之一: ClassParameterizedTypeGenericArrayTypeTypeVariableWildcardType

通过理解和使用这些数据绑定的图书馆知道足够的工作。

Kotlin的生活比较容易:

在Kotlin中,编写扩展函数是很容易的,所以你不必多次执行这种类型的代码。 只需创建一个帮助器内联函数,该函数使用泛化的泛型来通过类型并创建ParameterizedTypeReference

 inline fun <reified T: Any> typeRef(): ParameterizedTypeReference<T> = object: ParameterizedTypeReference<T>(){} 

现在你可以把@ edwin的例子改成:

 val response = restTemplate.exchange(request, typeRef<List<String>>()) 

我认为你需要实际使用RestTemplate.exechange方法,它的签名接受一个ParameterizedTypeReference<T> ,其中T可以是你的响应的通用类型(在你的情况下是List<User>

假设我有一个终端返回JSON格式的Jedi名字列表,如下所示

 ["Obi-wan","Luke","Anakin"] 

我想调用这个端点并得到一个List<String>作为结果,列表中包含来自JSON的Jedi名称。

然后我可以这样做:

 val endpoint = URI.create("http://127.0.0.1:8888/jedi.json") val request = RequestEntity<Any>(HttpMethod.GET, endpoint) val respType = object: ParameterizedTypeReference<List<String>>(){} val response = restTemplate.exchange(request, respType) val items: List<String> = response.body; println(items) //prints [Obi-wan, Luke, Anakin] 

注意我的ParameterizedTypeReference有一个List<String>类型的参数。 这就是诀窍。

而当我尝试它时,这对我来说很有用。