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

.markdown-body pre,.markdown-body pre>code.hljs{background:#fff;color:#000}.hljs-comment,.hljs-quote,.hljs-variable{color:green}.hljs-built_in,.hljs-keyword,.hljs-name,.hljs-selector-tag,.hljs-tag{color:#00f}.hljs-addition,.hljs-attribute,.hljs-literal,.hljs-section,.hljs-string,.hljs-template-tag,.hljs-template-variable,.hljs-title,.hljs-type{color:#a31515}.hljs-deletion,.hljs-meta,.hljs-selector-attr,.hljs-selector-pseudo{color:#2b91af}.hljs-doctag{color:grey}.hljs-attr{color:red}.hljs-bullet,.hljs-link,.hljs-symbol{color:#00b0e8}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}

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

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

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

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

image.png

不过在讲解这个之前,我们需要一些准备知识。

前置知识-Kotlin接口默认方法实现机制

大家应该都知道Kotlin接口的方法是可以默认实现的:

interface ICallback {

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

看着确实是对接口方法实现了默认重写,但真的是表面上这样的吗?子类真的不需要实现方法了吗?

下面我们简单证明下:搞一个java类实现这个接口,不重写任何方法,看看会不会报错

image.png

很明显报错了,提示我们子类需要重写接口的execute()方法,所以我们可以得出一个结论:Kotlin接口的方法的默认实现是伪实现

那kotlin的这个伪实现的实现原理是啥呢,这里我们反编译下java代码看一看:

image.png

很明显的看到,ICallback接口的方法还是个抽象方法,并没有默认实现(这就是为什么java直接实现这个接口会报错的原因)。其次还生成了一个DefaultImpls中间类,这个中间类提供了真正默认实现的execute()方法逻辑。

当我们kotlin子类实现这个接口时:

class ICallbackChild2 : ICallback

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

image.png

可以看到,编译器会默认帮助我们实现接口的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代码看下:

image.png

可以看到,借助了default关键字完成了接口方法的默认实现,并且没有生成上面的DefaultImpls中间类,算是一个很不错的优化。

如果我们项目中之前定义了很多的kotlin接口默认方法实现,那这个编译优化可以帮助你减少很多中间类的生成。

这里我们再次思考一下,我们突然增加了这个compile option消除了DefaultImpls类,但是假如之前的代码有使用到这个类怎么办呢?我们不太可能挨个每个地方的去调整原来的业务代码,这样工作量就非常大了。

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

@JvmDefaultWithCompatibility做个兼容

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

image.png

在我们增加了上面的-Xjvm-default=all之后,借助default消除了DefaultImpls这个帮助类后,我们还可以通过@JvmDefaultWithCompatibility这个注解指定哪个接口保留这个DefaultImpls类,因为其他地方可能需要显示调用这个类

这里我们还是以上面的ICallback接口为例:

@JvmDefaultWithCompatibility
interface ICallback {

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

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

image.png

可以看到,使用default实现了默认方法,并且DefaultImpls类依然存在,这就对过去kotlin接口的方法默认实现保持了兼容,尽量避免对业务逻辑的影响。

总结

其实kotlin之前有提供-Xjvm-default=all-compatibility和注解@JvmDefaultWithoutCompatibility搭配,不过这样对于业务开发不太友好,比如新增接口容易漏掉注解添加,再比如可能会对业务逻辑非public部分代码入侵过深等。

所以这里官方又提供了-Xjvm-default=all@JvmDefaultCompatibility搭配使用。希望本篇文章对你有所帮助。

新年快乐

作者:长安皈故里
链接:[https://juejin.cn/post/7190662820780834874]

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集在这里插入图片描述
二、源码解析合集
在这里插入图片描述

三、开源框架合集
在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值