刨下Kotlin | 9. @JvmOverloads 原理 & 一个小细节

简介: 刨下Kotlin | 9. @JvmOverloads 原理 & 一个小细节

0x1、原理


@JvmOverloads的作用告知编译器自动生成多个该方法的重载

就是不用自己写重载方法,kt会帮你自动生成,比如下面的代码:


@JvmOverloads 
fun search(name: String? = null, price: Float = 0.0f, kind: Int = -1) {}


等价于你在Java中声明三个重载方法:


void search(String name)
void search(String name, float price)
void search(String name, float price, int kind)


但!底层真的是转换成了这样三个方法吗?实际上 并不是!反编译下字节码:


网络异常,图片无法展示
|


生成了一个 search$default() 的方法,其他方法传参调用此方法。


令人不解的应该是&1、&2、&4,以及传参4,6,7 了,这些数字是干嘛的,还有怎么来的?


加上调用重载方法相关的代码:


fun main() {
    val book = Book()
    book.search("Kotlin")
    book.search("Kotlin", 66.6f)
    book.search("kotlin", kind = 1)
    book.search(price = 100.0f)
}


反编译下字节码:


网络异常,图片无法展示
|


传入的第五个参数依次为:6、4、2、5,调用传参少,值反而大,跟下6时searchBook$default走的逻辑:


6 → 0110
1 → 0001 | 6 & 1 → 0000 => 结果为0,不重置var1的值
2 → 0010 | 6 & 2 → 0010 => 结果不为0,重置var2的值
4 → 0100 | 6 & 4 → 0100 => 结果不为0,重置var3的值


看到这里,思维敏捷的朋友应该看出端倪了,不急,再试试4时:


4 → 0100
1 → 0001 | 4 & 4 → 0000 => 结果为0,不重置var1的值
2 → 0010 | 4 & 2 → 0000 => 结果为0,不重置var2的值
4 → 0100 | 4 & 4 → 0100 => 结果不为0,重置var3的值


还没get√到的同学想想这两个式子:6 = 0 + 2 + 44 = 0 + 0 + 4


懂了吧,就是每个参数对应一个值 → 2^(第几个参数-1)有传这个参数就不加,没传就加上。


不信?再加个参数试试:


@JvmOverloads
fun search(name: String? = null, price: Float = 0.0f, kind: Int = -1, author: String? = null) { }


看下反编译效果:


网络异常,图片无法展示
|


不难看出:


14 = 0 + 2 + 4 + 8
12 = 0 + 0 + 4 + 8
10 = 0 + 2 + 0 + 8


根据这个值来判断某位置的参数是否传参,没有直接赋初值,减少了非必要重载方法的生成,妙啊!!!


0x2、一个小细节


在实际开发中,@JvmOverloads最常用的场景莫过于 自定义View 时偷懒不用写这三个构造方法:


网络异常,图片无法展示
|


当你继承一个View,AS会贴心的提醒你,要不要加上这个@JvmOverloads:


网络异常,图片无法展示
|


点击之后自动加上,很香~


网络异常,图片无法展示
|


看着还行,当我们在布局文件中引用这个自定义的EditText,会发现,根本拿不到焦点,没办法输入???


其实跟下源码就知道了:


网络异常,图片无法展示
|


这个默认的值可不是0,应该是R.attr.editTextStyle,所以解决方法也很简单,把0改成这个值就好了:


网络异常,图片无法展示
|


其他控件也可能存在这种情况,当自定义View实现样式问题时,用到了@JvmOverloads,可以试着排查看看~


参考文献:



相关文章
|
1月前
|
Java 调度 Android开发
Android面试题之Kotlin中async 和 await实现并发的原理和面试总结
本文首发于公众号“AntDream”,详细解析了Kotlin协程中`async`与`await`的原理及其非阻塞特性,并提供了相关面试题及答案。协程作为轻量级线程,由Kotlin运行时库管理,`async`用于启动协程并返回`Deferred`对象,`await`则用于等待该对象完成并获取结果。文章还探讨了协程与传统线程的区别,并展示了如何取消协程任务及正确释放资源。
23 0
|
4月前
|
SQL 安全 Java
Android经典面试题之Kotlin中object关键字实现的是什么类型的单例模式?原理是什么?怎么实现双重检验锁单例模式?
Kotlin 单例模式概览 在 Kotlin 中,`object` 关键字轻松实现单例,提供线程安全的“饿汉式”单例。例如: 要延迟初始化,可使用 `companion object` 和 `lazy` 委托: 对于参数化的线程安全单例,结合 `@Volatile` 和 `synchronized`
59 6
|
Java Kotlin
Kotlin中与Java互操作与可空性、类型映射、属性访问、@JvmOverloads、@JvmField、@JvmStatic、@Throws和函数类型操作详解
Kotlin中与Java互操作与可空性、类型映射、属性访问、@JvmOverloads、@JvmField、@JvmStatic、@Throws和函数类型操作详解
96 0
|
XML 数据格式 Kotlin
Kotlin 异步 | Flow 限流的应用场景及原理
Kotlin 异步 | Flow 限流的应用场景及原理
839 0
|
XML 设计模式 分布式计算
Kotlin 异步 | Flow 应用场景及原理
Kotlin 异步 | Flow 应用场景及原理
202 0
|
Java 编译器 Kotlin
Kotlin之@JvmOverloads、@JvmStatic、@JvmField、@JvmInline等注解使用总结
`Kotlin`代码可以经过编译器转换成`VM虚拟机`能识别的字节码,所以`Java`与`Kotlin`可以互相进行调用。而由于`Java`与`Kotlin`语言特性的差异,当`Java`调用`Kotlin`代码时,可以在`Kotlin`代码中适当增加一些注解,从而更方便的调用`Kotlin`代码。
524 0
|
存储 IDE 编译器
Kotlin | 委托机制 & 原理 & 应用 彭旭锐
Kotlin | 委托机制 & 原理 & 应用 彭旭锐
597 0
Kotlin | 委托机制 & 原理 & 应用  彭旭锐
|
存储 Java API
深入理解Kotlin协程suspend工作原理(初学者也能看得懂)
深入理解Kotlin协程suspend工作原理(初学者也能看得懂)
深入理解Kotlin协程suspend工作原理(初学者也能看得懂)
|
消息中间件 Java 调度
抽丝剥茧聊Kotlin协程之协程启动原理
抽丝剥茧聊Kotlin协程之协程启动原理
抽丝剥茧聊Kotlin协程之协程启动原理
DHL
|
存储 前端开发 算法
为数不多的人知道的 Kotlin 技巧以及 原理解析(二)
这篇文章主要分析一些常见问题的解决方案,如果使用不当会对 性能 和 内存 造成的那些影响以及如何规避这些问题,文章中涉及的案例来自 Kotlin 官方、Stackoverflow、Medium 等等网站,都是平时看到,然后进行汇总和分析。
DHL
318 0
为数不多的人知道的 Kotlin 技巧以及 原理解析(二)