Kotlin:泛化的泛型似乎不适用于hash / equals比较

我有一个KClassInt的地图。 然后我有一个具有泛化类型的函数。 然后,我会期待以下情况,因此,给我关联与Boolean::classInt

 val kclassToInt = mapOf(Boolean::class to 1, Byte::class to 1, Short::class to 2) inline fun <reified T> myExpectations() = assertEquals(1, kclassToInt.getRaw(T::class), "Why doesn't it work? :'(") 

我迎接了Why doesn't it work? :'(. Expected <1>, actual <null>. Why doesn't it work? :'(. Expected <1>, actual <null>.从调用它像这样myExpectations<Boolean>()

然后我试图使用.java关闭,所以我使用Java的Class而不是Kotlin的KClass

 val classToInt = mapOf(Boolean::class.java to 1, Byte::class.java to 1, Short::class.java to 2) inline fun <reified T : Any> anotherExpectation() = assertEquals(1, classToInt.getRaw(T::class.java)) 

这一次,我再次迎来了断言错误: java.lang.AssertionError: Expected <1>, actual <null>.

最后,我尝试使用.javaClass而不是.java

 val javaClassToInt = mapOf(Boolean::class.javaClass to 1, Byte::class.javaClass to 1, Short::class.javaClass to 2) inline fun <reified T> pleaseWork() = assertEquals(1, javaClassToInt.getRaw(T::class.javaClass)) 

这一次真的很奇怪。 我被这个问候迎接: java.lang.AssertionError: Expected <1>, actual <2>. 这似乎是因为所有.javaClass引用KClassImpl

最后我诉诸了我不想做的事,用.qualifiedName

 val qnToInt = mapOf(Boolean::class.qualifiedName to 1, Byte::class.qualifiedName to 1, Short::class.qualifiedName to 2) inline fun <reified T> iKnowItWorks() = assertEquals(1, qnToInt.getRaw(T::class.qualifiedName)) 

哪一个当然有效,是我在我的实际使用情况下使用的: https : //github.com/Jire/kotmem/blob/master/src/main/kotlin/org/jire/kotmem/Process.kt

我相信Map中的关键类型是基本类型(Java int而不是Integer)的KClass实例。 函数中的KClass类型是盒装类型(Integer)的KClass实例,如Kotlin的指定类型对于JVM上的原语不正确所示。

虽然这两个KClass打印同样的东西,他们是不相同的,所以你的查找失败。

很可能你写了类似println(type.javaClass)这似乎是有道理的,但实际上不是因为它总是打印class kotlin.reflect.jvm.internal.KClassImpl ,因为这是内部实现类的KClass界面。

为什么type.javaClass工作? javaClass是一个扩展属性,它获得了作为接收者传递给它的任何值的运行时Java类。 其签名是:

 val <T : Any> T.javaClass: Class<T> 

typeKClass<T> type的完全有效值,所以type.javaClass的结果类型是Class<KClass<T>> 。 这已经几乎完全没有意义,除非你想要反思KClass实现类的符号。 由于type在运行时是KClassImpl实例,因此type.javaClass是一个Class实例,代表名为kotlin.reflect.jvm.internal.KClassImpl的类。

这有点混乱,绝对不是你想要做的。 如果你想打印一个类实例到屏幕上,你可以调用println(type) 。 如果您想获得与您所拥有的KClass实例相对应的Java Class实例,则可以使用java扩展特性: type.javajava的签名是:

 val <T : Any> KClass<T>.java: Class<T> 

所以如果type是一个KClass<T> ,那么type.java是一个Class<T>