扩展函数
Kotlin中可以给一个类额外添加这个类中没有的函数,即扩展函数。例如:
fun Int.dp2px(context: Context) {
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), context.resources.displayMetrics)
}
fun test () {
println(16.dp2px())
}
上述代码给Int类添加了一个扩展函数dp2px用于将dp转成px,在代码中可以直接对Int类型的变量调用dp2px函数,就好像Int类的其他固有函数一样。在扩展函数中可以通过this访问调用扩展函数的变量本身。
需要注意的是,扩展函数的调用者类型是静态声明的类型,而不是实际的运行时类型,例如:
fun Context.toString() : String {
return "context"
}
fun Activity.toString() : String {
return "activity"
}
fun printContext(context: Context) {
println(context.toString())
}
fun test(activity: Activity) {
printContext(activity)
}
上述代码调用test函数输出的结果是"context"而不是"activity"
扩展属性
Kotlin中还可以给一个类额外添加这个类中没有的属性,即扩展属性。例如:
val View.activity : Activity?
get() = this.context as? Activity
上述代码给View类添加了一个扩展属性activity,扩展属性并不是真的给该类添加了一个属性,所以只能通过getter和setter来访问和初始化
扩展函数和扩展属性的原理
class Test {
fun Int.dp2px(context: Context) {
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), context.resources.displayMetrics)
}
val View.activity : Activity?
get() = this.context as? Activity
}
通过将上述Kotlin代码转成字节码再反编译后如下:
public final class Test {
public final void dp2px(int $this$dp2px, @NotNull Context context) {
Intrinsics.checkNotNullParameter(context, "context");
float var10001 = (float)$this$dp2px;
Resources var10002 = context.getResources();
Intrinsics.checkNotNullExpressionValue(var10002, "context.resources");
TypedValue.applyDimension(1, var10001, var10002.getDisplayMetrics());
}
@Nullable
public final Activity getActivity(@NotNull View $this$activity) {
Intrinsics.checkNotNullParameter($this$activity, "$this$activity");
Context var10000 = $this$activity.getContext();
if (!(var10000 instanceof Activity)) {
var10000 = null;
}
return (Activity)var10000;
}
}
可以发现扩展函数和扩展属性的原理是在编译后生成了特定的函数,并将扩展类型的对象作为第一个参数传递进去。
对于Int类型的扩展函数dp2px实际是在Test类中生成一个dp2px函数,并接收Int类型的参数$this$dp2px作为第一个参数。
对于View类型的扩展属性activity实际是在Test类中生成一个getActivity函数,并接收View类型的参数$this$activity作为第一个参数