我之前每次跟别人分享 Kotlin 反射的时候,都会让大家小心点儿它,因为它一方面体积大,另一方面性能也差,不仅如此,还有一些小毛病,这些内容在我很久之前的一篇文章详细讨论了:Kotlin 反射你敢用吗?。那么时过境迁,今天的 Kotlin 反射怎么样了?
1. 不支持的 built-in Kotlin types
这个问题我们用当时的版本很容易复现,只需要运行下面的代码即可:
代码语言:javascript复制String::class.memberFunctions
但是,它在 1.2.60 已经修复了。也就是说,如果你使用 Kotlin 反射,请立刻马上更新到 1.2.60 以上的版本,这样就不会有 built-in types 的问题。
我们再简单唠叨几句,这个问题其实涉及到的都是 Kotlin 与 Java 存在映射关系的类,例如 String、枚举、Map 等等。
2. 运行性能差
Kotlin 反射耗时确实比 Java 反射耗时长,毕竟一方面没有 Java 虚拟机加成,Kotlin 的反射主要依赖于 @MetaData
注解,可参考:Kotlin 反射与 MetaData 的关系在混淆后浮出水面! 和 认识下 Kotlin 反射背后的男人:@Metadata,另一方面 Kotlin 反射提供的能力也比 Java 反射多很多(这主要与 Kotlin 本身的语法特性多是相对应的),所以付出多少得到多少,只要它的慢在合理范围内,我们其实也是可以接受的。
2.1 首次运行慢
涉及到注解解析和加载的问题,第一次运行必然慢,我用 1.3.0-rc-146 简单测试了一下:
单位:μs
构造对象 | 访问属性 | 修改属性 | 调用方法 | |
---|---|---|---|---|
Java 反射 | 2888.1 | 347.9 | 70.8 | 78.8 |
Kotlin 反射 | 1440742.1 | 61179.5 | 3496.7 | 199.3 |
第一次访问 Kotlin 反射确实要慢很多。
2.2 后续运行约为 Java 反射的 1.5~2 倍
后续运行由于是直接访问内存,因此性能上不会有数量级的差别:
单位:μs
构造对象 | 访问属性 | 修改属性 | 调用方法 | |
---|---|---|---|---|
Java 反射 | 15.5 | 16.8 | 11.0 | 26.3 |
Kotlin 反射 | 20.2 | 38.6 | 48.4 | 33.5 |
尽管仍然比 Java 反射耗时多一些,但对于使用反射的场景来说,这样通常也是可以接受的。
需要注意的是,过去的版本应该在后续的执行中也不会很慢,只是去年的文章我没有太注意这部分数据。
3. 2.5M的 Jar 包
当时提到了 2.5M 的 jar 包的问题,如果你是在 Server 端使用 Kotlin 反射,相信你也不会 care 这点儿包体积,更何况编译完之后也只有 400K 的样子,这对于 Android 应用来说也不是什么大问题,毕竟 Apk 的瘦身大头应该在资源上,也许你把设计出的某一个序列帧动画用代码实现了就可以省掉好几 MB。
4. 小结
其实之前让我觉得不安的主要是性能问题,显然这样看来倒也还好。而一些未完善的部分也在最近的版本得到了完善,因此 Kotlin 反射库的使用评级由“谨慎使用”上调为“合理使用”。