Kotlin 扩展函数实现原理

作为一个 Kotlin 用户,你可能非常熟悉这样的代码

1
2
3
fun EditText.string():String{
return this.getText()?.toString()?:""// this 实际上是 EditText 对象
}

这种延伸使我们开发更简单.现在我们可以这样做:

1
2
EditText etName = ...;
String name = etName.string()

它像 EditText 内部有 string() 函数

Kotlin 如何做到的?

通过做一些像反编译Apk 文件,我们可以理解Kotlin 如何实现的.

安装 Kotlin 命令行编译工具

如果你使用 Windows 系统,你可以从 Kotlin 官网解压 kotlin 编译到一个任意目录,然后添加这个目录到系统路径,bin 目录包含编译的脚本文件

如果你是 Mac 用户,你可以使用 HomeBrew 安装 kotlin

  • 如果你现在没有 HomeBrew, 你可以复制这行代码到命令行然后按下回车键

    1
    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
  • 如果你已经有 HomeBrew 你可以使用下面命令安装 kotlin

    1
    $ brew install kotlin
编译 Kotlin 文件

你可以只是输入 kotlinc ***.kt

使用 javap 理解*.class 文件

javap ***.class可以查看 kotlin 编译后的代码

例子

这有一个 kotlin 文件

1
2
3
4
5
6
7
fun String.first(num: Int): String {
return this.substring(0, num);
}

fun main(args: Array<String>) {
println("test".first(2))
}

使用 kotlincjavap之后,我们现在可以查看到 kotlin 在后台做了什么

源文件 编译后

使用javap之后的结果

1
2
3
4
5
6
$ javap FunctionExtensionDemoKt.class
Compiled from "FunctionExtensionDemo.kt"
public final class ca.six.kdemo.advanced.extension.FunctionExtensionDemoKt {
public static final java.lang.String first(java.lang.String, int);
public static final void main(java.lang.String[]);
}

我们现在看到 kotlinc 转换 String.first(int)first(String,int).这个方法像下面这样:

1
2
3
public static final String first(String src, int index){
return src.subString(0, index);
}

由此可以得知所谓的扩展函数不过就是自动生成一个带有当前对象的函数,当我们在 Kotlin 中调用扩展函数时,编译器将会调用自动生成的函数并且传入当前的对象.

总结

现在我们知道如何编译 kotlin 文件和查看结果.这个 扩展函数例子只是一个冰山一角,你可以现在开始查看 kotlin 是如何实现 lazy,lateinit,first-class function