专栏首页逮虾户Kotlin拓展函数的真身

Kotlin拓展函数的真身

kotlin也写了很长一段时间了,香是真的很香这个东西。但是很多东西也是不求甚解,都是直接开始用,但是为什么我也不关心。举个栗子,就拿拓展函数来说。

ImageExtension.kt
fun Double.dp(): Int {
    return ImageUtils.dip2px(this.toFloat())
}

fun Float.dp(): Int {
    return ImageUtils.dip2px(this.toFloat())
}

fun Int.dp(): Int {
    return ImageUtils.dip2px(this.toFloat())
}
复制代码
  val width = 18F.dp()

这个真的香吧,但是真实的这个语法糖到底是什么呢。

返本归元

先介绍个工具,Android Studio的工具栏有个tools/Kotlin/Show Kotlin ByteCode。然后在你的kotlin类上就可以直接看到kotlin类生成的字节码。

先抛问题在来分析。

java能不能调用到kotlin到拓展函数?

当然可以了。下面的代码块内就是18F.dp()的java写法。

int width=ImageExtensionKt.dp(18f);

惊不惊喜,意不意外。也就是说我们写的拓展函数其实也就是个静态方法,只是把我们拓展的类当作一个静态参数传递给了静态方法内。

深入探索

上面介绍的工具还是要用下,看看到底字节码上的拓展函数是怎么样的。

public final class com/xxxx/xxxx/ImageExtensionKt {
  // access flags 0x19
  public final static dp(D)I
    // annotable parameter count: 1 (visible)
    // annotable parameter count: 1 (invisible)
   L0
    LINENUMBER 47 L0
    DLOAD 0
    D2F
    INVOKESTATIC com/xxx/xxx/ImageUtils.dip2px (F)I
    IRETURN
   L1
    LOCALVARIABLE $this$dp D L0 L1 0
    MAXSTACK = 2
    MAXLOCALS = 2

  // access flags 0x19
  public final static dp(F)I
    // annotable parameter count: 1 (visible)
    // annotable parameter count: 1 (invisible)
   L0
    LINENUMBER 51 L0
    FLOAD 0
    INVOKESTATIC com/xxx/xxx/ImageUtils.dip2px (F)I
    IRETURN
   L1
    LOCALVARIABLE $this$dp F L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x19
  public final static dp(I)I
    // annotable parameter count: 1 (visible)
    // annotable parameter count: 1 (invisible)
   L0
    LINENUMBER 55 L0
    ILOAD 0
    I2F
    INVOKESTATIC com/xxx/xxx/ImageUtils.dip2px (F)I
    IRETURN
   L1
    LOCALVARIABLE $this$dp I L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1
}

简单分析下这个拓展函数类。

先给各位把字节码的基础简单的介绍下,表格会简单的把字节码里的类型和Java的类型做一次映射。

返回值

Type

类型

D

double

V

void

Z

boolean

C

char

B

byte

S

short

I

int

F

float

J

long

L

Object

操作符

操作符

类型

INVOKESTATIC

调用静态函数

INVOKESPECIAL

super

INVOKEVIRTUAL

调用当前类的某个方法

接下来开始逐行分析,public final static dp(D)I,dp代表方法名,而D则代表参数传入类型为Double,而I则代表返回类型是一个Int。用java来分析这个代码就是生成了一个dp的静态函数,传入参数是一个Double,返回参数是一个Int。

跳过行号分析,直接进入DLOAD 0, LOAD的含义是将一个局部变量加载到操作栈,D上面的表中代表了double,所以解释起来获取第一个传入参数。

D2F各位老哥可以用英文大声朗读下,double to float。然后把这个压入操作栈中。

INVOKESTATIC com/xxx/xxx/ImageUtils.dip2px (F)I 先参考下上面的操作符,INVOKESTATIC调用静态方法。com/xxx/xxx/ImageUtils.dip2px 类名方法名, (F)I入参返回值。同时将结果压入操作栈中。

IRETURN 返回上面栈的操作结果。

简单分析完字节码的操作之后,得出来的结论基本就是生成了一个dp的静态函数,以当前的拓展类作为第一个入参。

总结

这个文章其实吧是最近一个前同事去面试的时候被问到的,我其实也有点蒙蔽。但是kotlin和java最后编译出来的产物其实都是字节码,那么我们只要从它们最后编译出来的产物去逆向分析下,其实就能得到它们真实的原因了。

最后还是要说语法糖还是真香的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android 统计页面渲染时长

    文章开头还是先抛出几个小小的问题,大家在开发的时候有没有考虑过一个问题,onCreate方法执行完了是不是页面已经完全打开了呢?为什么呢?

    逮虾户
  • AndResGuard编译速度优化

    当前项目内用了腾讯的AndResGuard对资源文件的大小进行了一次深度优化。AndResGuard负责将文件名,arsc文件和R文件也进行了一次混淆,能把整体...

    逮虾户
  • 聊聊Android编译流程

    看起来我们貌似已经回答出了这个问题的答案,但是今天是来屠龙的,所以我们不能就这么简单的放过这个题目。

    逮虾户
  • 【数据挖掘】数据挖掘中应该避免的弊端

    1. 缺乏数据(Lack Data) 对于分类问题或预估问题来说,常常缺乏准确标注的案例。 例如:欺诈侦测(Fraud Detection):在上百万的交易中...

    陆勤_数据人网
  • 数据挖掘中最易栽的11个大坑

    按照Elder博士的总结,11大易犯错误:   1、缺乏数据   2、太关注训练   3、只依赖一项技术   4、提错了问题   5、只靠数据来说话   6...

    机器学习AI算法工程
  • 必看 :大数据挖掘中易犯的11大错误

    0 缺乏数据(LackData) 对于分类问题或预估问题来说,常常缺乏准确标注的案例。 例如: 欺诈侦测(FraudDetection):在上百万的交易中...

    灯塔大数据
  • 数据挖掘 | 避免弊端方法汇总大全,实用!

    导语:数据挖掘最重要的要素是分析人员的相关业务知识和思维模式。我们在掌握丰富的业务知识同时,如果能够按照正确的思维模式去思考问题,将会发现解决问题并不是很困难...

    灯塔大数据
  • 大数据挖掘中易犯的11大错误

    按照Elder博士的总结,这11大易犯错误包括: 0.缺乏数据(LackData) 1.太关注训练(FocusonTraining) 2.只依赖一项技术(Rel...

    小莹莹
  • 数据挖掘过程中绝不能犯这11大错误

    【摘要】当小孩子手拿一把锤子时,整个世界看起来就是一枚钉子。 1. 缺乏数据(Lack Data)   对于分类问题或预估问题来说,常常缺乏准确标注的案例。  ...

    CDA数据分析师
  • Celery用户手册 - Application

    该Application线程是安全(thread-safe)的,以便你可以使用多个不同的Application 配置. 组件和任务能共存于相同的进程空间。

    用户1416054

扫码关注云+社区

领取腾讯云代金券