前言
随着kotlin在Android日常开发中越来越频繁地使用,笔者觉得有必要对kotlin的一些特性做一些原理的梳理,所谓知其然知其所以然,才能更好让kotlin服务于我们的业务开发,所以会做一个kotlin系列,每个知识点简短,像个小卡片一样,便于理解和快速回顾。所有的源码为:Kotlin 标准库版本为1.9.10。
by关键字
by关键字是kotlin提供给开发者一个高效的语法糖,用于实现委托模式,委托本身是一种设计模式,允许将某些功能或属性的实现委托给另一个类或者对象。目的是提升代码的复用性和维护性。帮助我们提高编码效率。下文将by关键字的使用介绍及反编译看委托的实现细节。
使用
kotlin中的委托分为:属性委托、类委托。
- 委托属性 属性委托是将一个对象的getter和setter委托给另一个类的实例。通过修改getter/setter操作符的逻辑,来代理被委托的属性的读写行为,例如:
// 实现了getter和setter操作符函数,当其他属性被委托到这个类时,getter和setter将被其代理执行
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String { ... }
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { ... }
}
class Demo {
// 对test对象的getter和setter将被Delegate对象代理
private var test by Delegate()
}
- 委托接口 委托者和被委托者通过实现同一个接口来完成类行为的委托。例如:
// 定义一个通用接口
interface IDelegate {
fun getAAA() {}
fun getBBB() {}
}
// 使用委托
class Demo(delegate: IDelegate): IDelegate by delegate
原理
- 委托属性 我们通过反编译kotlin代码来看使用部分的demo的委托属性的实现
反编译后我们可以看到编译器帮我们生成了一个delegate实例,并抹掉了test参数,生成了与其名称对应的setter和getter函数,函数的实现交由delegate实现。
@Metadata(...)
public static final class Demo {
// $FF: synthetic field
static final KProperty[] $$delegatedProperties = new KProperty[]{Reflection.mutableProperty1(new MutablePropertyReference1Impl(Demo.class, "test", "getTest()Ljava/lang/String;", 0))};
private final Delegate test$delegate = new Delegate();
private final String getTest() {
return this.test$delegate.getValue(this, $$delegatedProperties[0]);
}
private final void setTest(String var1) {
this.test$delegate.setValue(this, $$delegatedProperties[0], var1);
}
}
- 委托接口 我们通过反编译kotlin代码来看使用部分的demo的委托接口的实现
从反编译出来的代码中我们可以看到kotlin编译器帮我们生成了接口类中所有的接口,并转交给构造时传入的delegate参数来实现对应接口的能力
@Metadata(...)
public final class Demo implements IDelegate {
// $FF: synthetic field
private final IDelegate $$delegate_0;
public Demo(@NotNull IDelegate delegate) {
Intrinsics.checkNotNullParameter(delegate, "delegate");
super();
this.$$delegate_0 = delegate;
}
public void getAAA() {
this.$$delegate_0.getAAA();
}
public void getBBB() {
this.$$delegate_0.getBBB();
}
}