Kotlin-通用函数成功在地图中存储了错误的类型

时间:2019-04-25 11:49:33

标签: generics kotlin

考虑以下代码:

val myarray = arrayListOf("hello", "world")
println(myarray)
println(myarray::class.java.name)

val arrayString = mapper.writeValueAsString(myarray)
println(arrayString)
println(arrayString::class.java.name)

val myMap = HashMap<String, String?>()
myMap["key"] = JsonPath.read<String>(arrayString, "$")

println(myMap["key"])
println(myMap["key"]!!::class.java.name)

此代码创建一个包含值“ hello”和“ world”的ArrayList,将列表转换为json字符串,读取json的根元素(这是被告知要返回字符串的通用函数),并将其存储在哈希图

此代码编译并运行无错误,并产生以下输出:

[hello, world]
java.util.ArrayList
["hello", "world"]
java.lang.String
["hello","world"]
net.minidev.json.JSONArray

myMap["key"]如何返回JSONArray? (记得myMap被声明为<String, String?>

Kotlin的类型在编译时检查,但是由于告知通用函数JsonPath.read返回一个String,因此编译会很好。

然后JsonPath.read似乎违反了合同,并返回了JSONArray而不是String。 Kotlin似乎没有键入check,而是允许在JSONArray中存储Map<String, String?>

除非我尝试将myMap["key"]用作String

,否则不会产生任何错误。

注意

此问题可以通过将读取json的行更改为:

myMap["key"] = ObjectMapper().writeValueAsString(JsonPath.read<String>(arrayString, "$"))

编辑

不使用json疯狂的代码示例:

fun <T> myFun(): T {
  return 7 as T
}

fun test() {
  val map = HashMap<String, String?>()
  map["key"] = myFun<String>()
  println(map["key"])
  println(map["key"]!!::class.java.name)
}

returns:
7
java.lang.Integer

2 个答案:

答案 0 :(得分:1)

Generic type information is erased at runtime

因此,基本上只是以您更新的示例并将其转换为运行时的结果(简化)为例:

<FlatList data={this.state.data} extraData={this.state} .../>

还要注意,您在这里使用的是unchecked cast(并且很可能fun myFun(): Any = 7 fun test() { val map = HashMap<Any, Any?>() map["key"] = myFun() println(map["key"]) println(map["key"]!!::class.java.name) // of course: Integer! } 也在使用它),这基本上就是编译器没有真正机会抓住问题的原因。或者换句话说,通过使用unchecked castJsonPath.read),您基本上对编译器说:“嘿...我知道我在做什么,不要打扰” ...所以它不会不用理会;-)

答案 1 :(得分:0)

类似的问题被跟踪为https://youtrack.jetbrains.com/issue/KT-12451

目前,即使Kotlin知道调用类型的泛型类型,在传递给另一个泛型方法之前,Kotlin不会检查泛型方法调用的结果。这种行为与Java中的行为相同,尽管可能还有一些改进的空间。