Kotlin:Reified仿制药似乎不适合哈希/等于比较

时间:2015-11-29 06:39:44

标签: java reflection kotlin

我有KClassInt的地图。然后我有一个具有固定泛型类型的函数。因此,我希望以下情况能够提供与Int相关联的Boolean::class

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>.打电话给我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

2 个答案:

答案 0 :(得分:3)

你很可能写过类似println(type.javaClass)的内容似乎有意义,但实际上并不是因为它始终打印class kotlin.reflect.jvm.internal.KClassImpl,因为这是内部实现类KClass界面。

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

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

typeKClass<T>类型的完全有效值,因此type.javaClass的结果类型为Class<KClass<T>>。除非您想要内省KClass实现类的符号,否则这几乎完全没有意义。由于type是运行时的KClassImpl实例,type.javaClass实际上是一个Class实例,表示名为kotlin.reflect.jvm.internal.KClassImpl的类。

这有点令人困惑,绝对不是你想要做的。如果要将类实例打印到屏幕,只需调用println(type)即可。如果要获取与Class实例对应的Java KClass实例,可以使用java扩展属性:type.javajava的签名是:

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

因此,如果typeKClass<T>,那么type.java就是Class<T>

答案 1 :(得分:1)

我相信Map中的键类型是基本类型的KClass个实例(Java int而不是Integer)。函数中的具体类型是盒装类型(整数)的KClass实例,如Are Kotlin's reified types incorrect for primitives on the JVM?中所示

虽然这两个KClass打印的内容相同,但它们并不相同,因此您的查找失败。