【kotlin】::class 引发的效率问题
2021-12-07 本文已影响0人
littlefogcat
今日遇到一个kotlin问题,synchronized(MyClass:class)
效率比synchronized(MyClass:class.java)
低很多,想了解原因,故研究一下。
一、对应Java代码
以下代码:
class MyClass {}
fun main() {
val var1 = MyClass::class
val var2 = MyClass::class.java
println("$var1, $var2")
}
通过编译器反编译字节码,查看其对应的Java代码:
public static final void main() {
KClass var1 = Reflection.getOrCreateKotlinClass(MyClass.class);
Class var2 = MyClass.class;
String var3 = var1 + ", " + var2;
System.out.println(var3);
}
可以发现:
MyClass::class
对应的Java代码为Reflection.getOrCreateKotlinClass(MyClass.class)
;MyClass::class.java
对应的Java代码为MyClass.class
;
二、源码分析
Reflection.getOrCreateKotlinClass
代码如下:
public static KClass getOrCreateKotlinClass(Class javaClass) {
return factory.getOrCreateKotlinClass(javaClass);
}
可以发现,这个factory
其实是一个ReflectionFactory
类型的对象,查看对应方法:
public KClass getOrCreateKotlinClass(Class javaClass) {
return new ClassReference(javaClass);
}
也就是说,每次调用MyClass::class
都会新创建一个ClassReference
对象?
不是的。其实factory
的真实类型是ReflectionFactoryImpl
,其getOrCreateKotlinClass
方法如下:
public KClass getOrCreateKotlinClass(Class javaClass) {
return KClassCacheKt.getOrCreateKotlinClass(javaClass);
}
KClassCacheKt
类包含了一个缓存的Map,当调用getOrCreateKotlinClass
方法时,会从缓存中读取对应的KClass类型;如果缓存中没有的话,就创建一个对应的KClass对象并保存在Map中。
三、总结
在kotlin中第一次调用MyClass::class
的时候,会创建一个KClassImpl
对象并保存在缓存中;之后再次调用就直接从缓存中返回之。而调用MyClass::class.java
时,则直接通过类加载器返回对应的Java类对象。
而开头遇到的效率问题,其实是MyClass::class
第一次调用时创建KClass对象的额外开销。当然,在大多数情况下,并不会造成多大影响;在高性能需求的场景,可以提前调用MyClass::class
创建KClass缓存。