今日写这篇文章主要是有两个原因:

  1. 不是为了卷,仅仅为了希望能在明日过年前升到5级,拿个优秀创作者的称谓,提早祝大家新年快乐;

  2. 最近项目kotlin插件升级到了1.6.21,咬着牙把官方英文文档看了下,发现一些有用的常识共享给大家;

本篇文章主要是介绍下1.6.20供给了的一个新特性-Xjvm-default=all和调配使用的@JvmDefaultWithCompatibility注解:

@JvmDefaultWithCompatibility优化小技巧,了解一下~

不过在讲解这个之前,咱们需求一些准备常识。

前置常识-Kotlin接口默许办法完结机制

大家应该都知道Kotlin接口的办法是能够默许完结的:

interface ICallback {
    fun execute() {
        println("execute...")
    }
}

看着确实是对接口办法完结了默许重写,但真的是表面上这样的吗?子类真的不需求完结办法了吗?

下面咱们简单证明下:搞一个java类完结这个接口,不重写任何办法,看看会不会报错

@JvmDefaultWithCompatibility优化小技巧,了解一下~

很明显报错了,提示咱们子类需求重写接口的execute()办法,所以咱们能够得出一个定论:Kotlin接口的办法的默许完结是伪完结

那kotlin的这个伪完结的完结原理是啥呢,这儿咱们反编译下java代码看一看:

@JvmDefaultWithCompatibility优化小技巧,了解一下~

很明显的看到,ICallback接口的办法仍是个笼统办法,并没有默许完结(这便是为什么java直接完结这个接口会报错的原因)。其次还生成了一个DefaultImpls中心类,这个中心类供给了真实默许完结的execute()办法逻辑。

当咱们kotlin子类完结这个接口时:

class ICallbackChild2 : ICallback

这样写并不会产生任何报错,咱们反编译成java代码看下:

@JvmDefaultWithCompatibility优化小技巧,了解一下~

能够看到,编译器会默许协助咱们完结接口的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代码看下:

@JvmDefaultWithCompatibility优化小技巧,了解一下~

能够看到,凭借了default关键字完结了接口办法的默许完结,而且没有生成上面的DefaultImpls中心类,算是一个很不错的优化。

如果咱们项目中之前界说了许多的kotlin接口默许办法完结,那这个编译优化能够协助你削减许多中心类的生成。

这儿咱们再次考虑一下,咱们忽然添加了这个compile option消除了DefaultImpls类,但是假设之前的代码有使用到这个类怎么办呢?咱们不太或许挨个每个地方的去调整本来的事务代码,这样工作量就非常大了。

所以kotlin官方交心的供给了@JvmDefaultWithCompatibility注解做了一个兼容处理,接下来听我逐个介绍。

@JvmDefaultWithCompatibility做个兼容

先上一张官方图,最需求注意的便是第一行和最后一行:

@JvmDefaultWithCompatibility优化小技巧,了解一下~

在咱们添加了上面的-Xjvm-default=all之后,凭借default消除了DefaultImpls这个协助类后,咱们还能够经过@JvmDefaultWithCompatibility这个注解指定哪个接口保留这个DefaultImpls类,由于其他地方或许需求显现调用这个类

这儿咱们仍是以上面的ICallback接口为例:

@JvmDefaultWithCompatibility
interface ICallback {
    fun execute() {
        println("execute...")
    }
}

咱们反编译成java代码看下:

@JvmDefaultWithCompatibility优化小技巧,了解一下~

能够看到,使用default完结了默许办法,而且DefaultImpls类依然存在,这就对过去kotlin接口的办法默许完结保持了兼容,尽量避免对事务逻辑的影响。

总结

其实kotlin之前有供给-Xjvm-default=all-compatibility和注解@JvmDefaultWithoutCompatibility调配,不过这样关于事务开发不太友爱,比如新增接口容易漏掉注解添加,再比如或许会对事务逻辑非public部分代码侵略过深等。

所以这儿官方又供给了-Xjvm-default=all@JvmDefaultCompatibility调配使用。希望本篇文章对你有所协助。

新年快乐

@JvmDefaultWithCompatibility优化小技巧,了解一下~