前言
Kotlin扩展函数为我们提供了方便的开发调用,不用通过继承或者装饰者模式来实现功能的扩展,它的内部原理其实是通过封装了public static final method
(调用者对象作为参数)方法,效率上并没有什么提升。
扩展函数定义
1.在ExtentKotlin.kt
中定义扩展函数:
fun String.printlnHaHa(){
var result = "haha$this"
println(result)
}
2.外部使用扩展函数:
open class MediaPlayer(var path:String) {
fun play(path:String){
"aa".printlnHaHa()
}
}
3.查看字节码生成,反编译为java类
AS -> tools -> Kotlin -> show Kotlin byte code -> Decompile
4.ExtentKotlin.kt中的扩展函数反编译
public final class ExtentKotlinKt {
public static final void printlnHaHa(@NotNull String $this$printlnHaHa) {
Intrinsics.checkParameterIsNotNull($this$printlnHaHa, "$this$printlnHaHa");
String result = "haha" + $this$printlnHaHa;
System.out.println(result);
}
}
可以看到扩展函数语法糖背后的实现原理
1.生成了一个final类ExtentKotlinKt
2.将扩展函数转变为了public static final 类型的方法,方法参数是类扩展函数类型的参数,方法内部使用这个函数做了操作处理
3.根据分析从而得知其他地方就是通过调用ExtentKotlinKt的static final方法实现的调用。
- 扩展函数的外部调用
public class MediaPlayer {
@NotNull
private String path;
public final void play(@NotNull String path) {
Intrinsics.checkParameterIsNotNull(path, "path");
// 在这里调用了外部扩展类的静态方法,并将调用对象传递给扩展函数了
ExtentKotlinKt.printlnHaHa("aa");
}
@NotNull
public final String getPath() {
return this.path;
}
public final void setPath(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
this.path = var1;
}
public MediaPlayer(@NotNull String path) {
Intrinsics.checkParameterIsNotNull(path, "path");
super();
this.path = path;
}
}
inline关键字原理
还以上面的例子分析扩展函数,在扩展函数加上inline关键字进行修饰,查看反编译后的效果
1.inline关键字修饰扩展函数
inline fun String.printlnHaHa(){
var result = "haha$this"
println(result)
}
2.查看反编译后对应的java文件
public final class ExtentKotlinKt {
public static final void printlnHaHa(@NotNull String $this$printlnHaHa) {
int $i$f$printlnHaHa = 0;
Intrinsics.checkParameterIsNotNull($this$printlnHaHa, "$this$printlnHaHa");
String result = "haha" + $this$printlnHaHa;
System.out.println(result);
}
}
与扩展函数的实现一样并没有什么改变,还是public static final方法
3.外部类使用inline关键字的扩展函数
open class MediaPlayer(var path:String) {
fun play(path:String){
"aa".printlnHaHa()
}
}
4.反编译外部类
public class MediaPlayer {
@NotNull
private String path;
public final void play(@NotNull String path) {
Intrinsics.checkParameterIsNotNull(path, "path");
/*
这里的调用发生了改变,不再是直接调用
ExtentKotlinKt.printlnHaHa("aa"),
而是直接将方法体中的内容复制了一遍执行,
这么做可以减少方法的查找和调用,效率上有所提高了
*/
String $this$printlnHaHa$iv = "aa";
int $i$f$printlnHaHa = false;
String result$iv = "haha" + $this$printlnHaHa$iv;
System.out.println(result$iv);
}
@NotNull
public final String getPath() {
return this.path;
}
public final void setPath(@NotNull String var1) {
Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
this.path = var1;
}
public MediaPlayer(@NotNull String path) {
Intrinsics.checkParameterIsNotNull(path, "path");
super();
this.path = path;
}
总结
inline内联函数会复制一遍函数内部方法体的实现,这样会让使用处的代码膨胀. 所以官方极力建议, 内联函数的代码不建议超过 3 行. 控制在 1~3 行代码是最佳的。
网友评论