@JvmDefaultWithCompatibility优化小技巧,了解一下~
今天写这篇文章主要是有两个原因:
不是为了卷,只是为了希望能在明天过年前升到5级,拿个
优秀创作者
的称号,提前祝大家新年快乐;最近项目kotlin插件升级到了1.6.21,咬着牙把官方英文文档看了下,发现一些有用的知识分享给大家;
本篇文章主要是介绍下1.6.20提供了的一个新特性-Xjvm-default=all
和搭配使用的@JvmDefaultWithCompatibility
注解:
不过在讲解这个之前,我们需要一些准备知识。
前置知识-Kotlin接口默认方法实现机制
大家应该都知道Kotlin接口的方法是可以默认实现的:
interface ICallback {
fun execute() {
println("execute...")
}
}
看着确实是对接口方法实现了默认重写,但真的是表面上这样的吗?子类真的不需要实现方法了吗?
下面我们简单证明下:搞一个java类实现这个接口,不重写任何方法,看看会不会报错:
很明显报错了,提示我们子类需要重写接口的execute()
方法,所以我们可以得出一个结论:Kotlin接口的方法的默认实现是伪实现
。
那kotlin的这个伪实现的实现原理是啥呢,这里我们反编译下java代码看一看:
很明显的看到,ICallback
接口的方法还是个抽象方法,并没有默认实现(这就是为什么java直接实现这个接口会报错的原因)。其次还生成了一个DefaultImpls
中间类,这个中间类提供了真正默认实现的execute()
方法逻辑。
当我们kotlin子类实现这个接口时:
class ICallbackChild2 : ICallback
这样写并不会发生任何报错,我们反编译成java代码看下:
可以看到,编译器会默认帮助我们实现接口的execute()
方法,并调用了DefaultImpls
类中的execute()
完成了默认实现。
以上就是kotlin接口方法默认实现的原理,真正的实现逻辑通过一个默认生成的DefaultImpls
类去完成。
现在我们思考下,为什么kotlin要这么实现呢,直接借助java的default
关键字不可以吗,上面这种实现还多了一个类的开销?
Kotlin官方当然也发现了这个问题,所以在kotlin1.6.20提供了-Xjvm-default=all
这个compile option来进行优化,接下来听我一一介绍。
-Xjvm-default=all
登场
想要使用这个,需要在Android Studio中build.gradle增加下面配置:
kotlinOptions {
jvmTarget = '1.8'
freeCompilerArgs += "-Xjvm-default=all"
}
这个完成之后,我们还是拿上面的接口作为例子讲解:
interface ICallback {
fun execute() {
println("execute...")
}
}
我们再次反编译成java代码看下:
可以看到,借助了default
关键字完成了接口方法的默认实现,并且没有生成上面的DefaultImpls
中间类,算是一个很不错的优化。
如果我们项目中之前定义了很多的kotlin接口默认方法实现,那这个编译优化可以帮助你减少很多中间类的生成。
这里我们再次思考一下,我们突然增加了这个compile option消除了DefaultImpls
类,但是假如之前的代码有使用到这个类怎么办呢?我们不太可能挨个每个地方的去调整原来的业务代码,这样工作量就非常大了。
所以kotlin官方贴心的提供了@JvmDefaultWithCompatibility
注解做了一个兼容处理,接下来听我一一介绍。
@JvmDefaultWithCompatibility
做个兼容
先上一张官方图,最需要注意的就是第一行和最后一行:
在我们增加了上面的-Xjvm-default=all
之后,借助default
消除了DefaultImpls
这个帮助类后,我们还可以通过@JvmDefaultWithCompatibility
这个注解指定哪个接口保留这个DefaultImpls
类,因为其他地方可能需要显示调用这个类。
这里我们还是以上面的ICallback
接口为例:
@JvmDefaultWithCompatibility
interface ICallback {
fun execute() {
println("execute...")
}
}
我们反编译成java代码看下:
可以看到,使用default
实现了默认方法,并且DefaultImpls
类依然存在,这就对过去kotlin接口的方法默认实现保持了兼容,尽量避免对业务逻辑的影响。
总结
其实kotlin之前有提供-Xjvm-default=all-compatibility
和注解@JvmDefaultWithoutCompatibility
搭配,不过这样对于业务开发不太友好,比如新增接口容易漏掉注解添加,再比如可能会对业务逻辑非public部分代码入侵过深等。
所以这里官方又提供了-Xjvm-default=all
和@JvmDefaultCompatibility
搭配使用。希望本篇文章对你有所帮助。
新年快乐
链接:https://juejin.cn/post/7190662820780834874
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。