Kotlin language get class at runtime

2020-04-07 02:59发布

问题:

Let's say that we have the following:

val person = "Bill"

Could someone explain the difference between these two:

val kClass1 = person.javaClass.kotlin    

vs

val kClass2 = person::class

When I should call the one instead of the other?

Any source code example would be appreciated.

回答1:

The main reason there are two ways to achieve the same thing, namely get the Kotlin class of an object, is because prior to Kotlin 1.1, the ::class literal did not support the expression on its left-hand side. So if you're using Kotlin 1.0, your only option is .javaClass.kotlin, otherwise you're fine with either of them. This is the reason "Kotlin in Action" uses the .javaClass.kotlin syntax: it was written before the Kotlin 1.1 release.

There's also a minor difference in the types of these expressions. For example, in the following code

interface T

fun f1(x: T) = x::class
fun f2(x: T) = x.javaClass.kotlin

f1's type is KClass<out T>, but f2's type is KClass<T>. This is actually an oversight in the javaClass declaration: KClass<out T> is more correct in this case, because x's class is not necessarily T, but can also be a subclass of T.

Otherwise these two expressions (x.javaClass.kotlin and x::class) are completely equivalent in terms of produced bytecode and runtime performance. I prefer x::class because it's shorter and reads better.



回答2:

person.javaClass.kotlin creates new Kotlin class reference object from Java class. So it makes sense only if you have only java class object.

So you should use person::class because in this case you just get Kotlin class directly without additional objects allocation



回答3:

No one can replace another one, They both have reason to exist.

IF you get a KClass from a variable that can't be null then you prefer to using foo::class since javaClass.kotlin create a new instance each time, for example:

assert(foo::class === foo::class); 
assert(foo.javaClass.kotlin !== foo.javaClass.kotlin); 

IF you get a KClass from a nullable variable then prefer to using as below:

val value:Int? = 1;

val type = value?.javaClass?.kotlin;

IF you get a java Class from kotlin you want to transform to KClass then using Class.kotlin for example:

val javaClass:Class<Integer> = ...;
val kotlinClass:KClass<Integer> = javaClass.kotlin;