Kotlin委托的使用和原理
什么是委托
委托就是一种通过将实际工作交给其他对象来实现的设计模式;kotlin给我们提供了by关键词实现委托.
类委托
首先来看类委托,类委托的意思就是A中持有一个B的实例,A实现某个功能都交给B来实际执行.我们来看代码:
kotlin
interface IVehicle {
fun drive():String
}
class Car(private val vehicle: IVehicle) : IVehicle by vehicle
fun main(){
val car = Car(object :IVehicle{
override fun drive(): String {
return "drive car"
}
})
println(car.drive())
}
Car类实现了IVehicle接口及持有了一个IVehicle实例,并通过by关键词将逻辑委托给vehicle.反编译成java代码看下:
kotlin
public final class Car implements IVehicle {
private final IVehicle vehicle;
public Car(@NotNull IVehicle vehicle) {
Intrinsics.checkNotNullParameter(vehicle, "vehicle");
super();
this.vehicle = vehicle;
}
@NotNull
public String drive() {
return this.vehicle.drive();
}
}
Car这个类实现了IVehicle,且通过by属性委托,编译器自动生成了drive()接口方法的实现,并调用构造方法中传入的委托对象的drive()方法.
属性委托
属性委托就是指一个类实现了ReadWriteProperty接口,同时把一个属性的get和set方法委托给这个委托类.我们来看代码:
kotlin
class PropertyDelegate: ReadWriteProperty<Any?, Int> {
var v = 0
override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
println("getValue")
return v
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
println("setValue")
v = value * value
}
}
fun main(){
var propertyValue :Int by PropertyDelegate()
propertyValue = 10
println(propertyValue)
}
这段代码中首先声明了一个委托类,实现了setValue和getValue两个方法,实际上这两个方法都是运算符重载方法,以getValue为例,它其实是这个方法:
kotlin
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
public override operator fun getValue(thisRef: T, property: KProperty<*>): V
在main方法中通过by关键字把value委托给委托类实例,只要对value赋值或获取value时,就会调用到委托类的getValue和setValue方法.
我们看下反编译后的代码:
typescript
public final class PropertyDelegate implements ReadWriteProperty {
private int v;
public final int getV() {
return this.v;
}
public final void setV(int var1) {
this.v = var1;
}
@NotNull
public Integer getValue(@Nullable Object thisRef, @NotNull KProperty property) {
Intrinsics.checkNotNullParameter(property, "property");
String var3 = "getValue";
System.out.println(var3);
return this.v;
}
// $FF: synthetic method
// $FF: bridge method
public Object getValue(Object var1, KProperty var2) {
return this.getValue(var1, var2);
}
public void setValue(@Nullable Object thisRef, @NotNull KProperty property, int value) {
Intrinsics.checkNotNullParameter(property, "property");
String var4 = "setValue";
System.out.println(var4);
this.v = value * value;
}
// $FF: synthetic method
// $FF: bridge method
public void setValue(Object var1, KProperty var2, Object var3) {
this.setValue(var1, var2, ((Number)var3).intValue());
}
}
public final class PropertyDelegateKt {
// $FF: synthetic field
static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty0(new MutablePropertyReference0Impl(PropertyDelegateKt.class, "propertyValue", "<v#0>", 1))};
public static final void main() {
PropertyDelegate var10000 = new PropertyDelegate();
KProperty var1 = $$delegatedProperties[0];
PropertyDelegate propertyValue = var10000;
propertyValue.setValue((Object)null, var1, 10);
int var2 = propertyValue.getValue((Object)null, var1);
System.out.println(var2);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
在main方法中,生成了一个PropertyDelegate代理类,当对propertyValue赋值时就会调用代理类的setValue方法,当获取propertyValue值的时候就调用代理类的getValue方法.
属性委托还有一种用法,看一下代码
kotlin
fun main(){
val map:MutableMap<String,String> = mutableMapOf()
map["name"] = "name1"
var name by map
println(name)
name = "name2"
}
当访问/修改name时,就会从map中获取key为name的value值并返回,看下反编译后的代码:
arduino
public final class MapDelegateKt {
// $FF: synthetic field
static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty0(new MutablePropertyReference0Impl(MapDelegateKt.class, "name", "<v#0>", 1))};
public static final void main() {
Map map = (Map)(new LinkedHashMap());
map.put("name", "name1");
KProperty var2 = $$delegatedProperties[0];
Object var4 = null;
Object var3 = MapsKt.getOrImplicitDefaultNullable(map, var2.getName());
System.out.println(var3);
var4 = null;
String var5 = "name2";
map.put(var2.getName(), var5);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
- 通过反射生成了一个
KProperty
类型对象变量$$delegatedProperties
,通过这个对象的getName()
我们就能拿到变量名称,比如这里的"name"变量名; - 最终调用了
MapsKt.getOrImplicitDefaultNullable
方法,去map
散列表去查找"name"这个key对应的value;
Kotlin提供的属性委托
-
延迟属性Lazy
kotlinval count : Int by lazy{ println("init") 0 }
lazy() 接受一个lambda表达式并返回一个Lazy实例的函数,只有当第一次调用count时,count变量才会初始化,也就是调用lambda表达式.lazy()的实现是一个SynchronizedLazyImpl()实例
kotlinprivate class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable { private var initializer: (() -> T)? = initializer @Volatile private var _value: Any? = UNINITIALIZED_VALUE // final field is required to enable safe publication of constructed instance private val lock = lock ?: this override val value: T get() { val _v1 = _value if (_v1 !== UNINITIALIZED_VALUE) { @Suppress("UNCHECKED_CAST") return _v1 as T } return synchronized(lock) { val _v2 = _value if (_v2 !== UNINITIALIZED_VALUE) { @Suppress("UNCHECKED_CAST") (_v2 as T) } else { val typedValue = initializer!!() _value = typedValue initializer = null typedValue } } } override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet." private fun writeReplace(): Any = InitializedLazyImpl(value) }
-
可观察属性Observable
kotlinvar age : Int by Delegates.observable(0) { _, oldValue, newValue -> println("old value : $oldValue, new value : $newValue") newValue > oldValue }
Delegates.observable()接受两个参数,一个是初始值,一个是修改时的lambda表达式:
kotlinpublic abstract class ObservableProperty<V>(initialValue: V) : ReadWriteProperty<Any?, V> { private var value = initialValue /** * The callback which is called before a change to the property value is attempted. * The value of the property hasn't been changed yet, when this callback is invoked. * If the callback returns `true` the value of the property is being set to the new value, * and if the callback returns `false` the new value is discarded and the property remains its old value. */ protected open fun beforeChange(property: KProperty<*>, oldValue: V, newValue: V): Boolean = true /** * The callback which is called after the change of the property is made. The value of the property * has already been changed when this callback is invoked. */ protected open fun afterChange(property: KProperty<*>, oldValue: V, newValue: V): Unit {} public override fun getValue(thisRef: Any?, property: KProperty<*>): V { return value } public override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) { val oldValue = this.value if (!beforeChange(property, oldValue, value)) { return } this.value = value afterChange(property, oldValue, value) } }