Kotlin: los generics reificados no parecen funcionar bien para comparaciones hash / iguales

Tengo un map de KClass a Int . Luego tengo una function que tiene un tipo genérico reificado. Entonces esperaría la siguiente situación, por lo tanto, para darme el Int asociado con 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? :'(") 

Me recibieron con Why doesn't it work? :'(. Expected <1>, actual <null>. Why doesn't it work? :'(. Expected <1>, actual <null>. De una llamada a este como myExpectations<Boolean>() .

Luego traté de usar .java , así que estaba usando la Class de Java en lugar de KClass de Kotlin.

 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)) 

Esta vez, me saludó de nuevo el error de aserción: java.lang.AssertionError: Expected <1>, actual <null>.

Finalmente intenté usar .javaClass lugar de .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)) 

Esta vez fue realmente extraño. Fui recibido con esto: java.lang.AssertionError: Expected <1>, actual <2>. Esto parece ser porque todos .javaClass refieren a KClassImpl .

Finalmente recurrí a lo que no quería hacer, uso .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)) 

Lo que por supuesto funciona y es lo que uso en mi caso de uso real: https://github.com/Jire/kotmem/blob/master/src/main/kotlin/org/jire/kotmem/Process.kt

Creo que los types de key en su Mapa son instancias KClass para los types primitivos (Java int en vez de Integer). El tipo reificado en la function es la instancia de KClass para el tipo KClass (Entero), como se ve en ¿Los types reificados de Are Kotlin son incorrectos para las primitivas en la JVM?

Si bien estas dos KClass imprimen como la misma cosa, no son iguales, por lo que su búsqueda falla.

Lo más probable es que haya escrito algo como println(type.javaClass) que puede parecer que tiene sentido, pero en realidad no lo hace porque siempre imprime la class kotlin.reflect.jvm.internal.KClassImpl , ya que esa es la class de implementación interna del Interfaz KClass .

¿Por qué type.javaClass funciona de esa manera? javaClass es una propiedad de extensión que obtiene una class de Java en time de ejecución de cualquier valor que se le pase como un receptor. Su firma es:

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

type es un valor perfectamente válido de tipo KClass<T> , por lo que el tipo resultante de Class<KClass<T>> es Class<KClass<T>> . Esto ya casi no tiene sentido a less que desee introspectar los símbolos de la class de implementación KClass . Dado que type es una instancia de KClassImpl en time de ejecución, type.javaClass es efectivamente una instancia de Class representa la class llamada kotlin.reflect.jvm.internal.KClassImpl .

Esto es un poco confuso y definitivamente no es lo que querías hacer. Si desea imprimir una instancia de class en la pantalla, puede simplemente llamar a println(type) . Si desea get una instancia de la Class Java correspondiente a la instancia de KClass que tiene, puede usar la propiedad de extensión java : type.java . la firma de java es:

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

Entonces, si type es una KClass<T> , entonces type.java es una Class<T> .