I have a map of KClass
to Int
. I then have a function which has a reified generic type. I'd then expect the following situation, thus, to give me the Int
associated with 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? :'(")
I'm greeted with Why doesn't it work? :'(. Expected <1>, actual <null>.
from a call to it like this myExpectations<Boolean>()
.
I then tried to use .java
off, so I was using Java's Class
rather than Kotlin's 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))
This time I was again greeted by assertion error: java.lang.AssertionError: Expected <1>, actual <null>.
Finally I tried using .javaClass
rather than .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))
This time it was really strange. I was greeted with this: java.lang.AssertionError: Expected <1>, actual <2>.
This seems to be because all .javaClass
refer to KClassImpl
.
Finally I resorted to what I didn't want to do, use .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))
Which of course works and is what I use in my actual use case: https://github.com/Jire/kotmem/blob/master/src/main/kotlin/org/jire/kotmem/Process.kt
Most likely you've written something like println(type.javaClass)
which may seem to make sense, but actually doesn't because it always prints class kotlin.reflect.jvm.internal.KClassImpl
, since that is the internal implementation class of the KClass
interface.
Why does type.javaClass
work that way? javaClass
is an extension property which gets a runtime Java class of any value passed to it as a receiver. Its signature is:
val <T : Any> T.javaClass: Class<T>
type
is a perfectly valid value of type KClass<T>
, so type.javaClass
's resulting type is Class<KClass<T>>
. This is already almost entirely meaningless unless you want to introspect symbols of the KClass
implementation class. Since type
is a KClassImpl
instance at runtime, type.javaClass
is effectively a Class
instance representing the class named kotlin.reflect.jvm.internal.KClassImpl
.
This is a bit confusing and definitely not what you wanted to do. If you want to print a class instance to the screen, you can just call println(type)
. If you want to obtain a Java Class
instance corresponding to the KClass
instance you have, you can use the java
extension property: type.java
. java
's signature is:
val <T : Any> KClass<T>.java: Class<T>
So if type
is a KClass<T>
, then type.java
is a Class<T>
.
I believe that the key types in your Map are KClass
instances for the primitive types (Java int rather than Integer). The reified type in the function is the KClass
instance for the boxed type (Integer), as seen in Are Kotlin's reified types incorrect for primitives on the JVM?
Whilst these two KClass
s print as the same thing, they are not equal, so your lookup fails.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With