Moosphan / Android-Daily-Interview

:pushpin:每工作日更新一道 Android 面试题,小聚成河,大聚成江,共勉之~

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

2019-07-26:什么是委托属性?请简要说说其使用场景和原理?

Moosphan opened this issue · comments

2019-07-26:什么是委托属性?请简要说说其使用场景和原理?

把一件事委托给其他人来做。如kotlin中的by
var p: String by Delegate(),get和set委托给Delegate的getValue()方法和setValue()方法

居然没人说,很奇怪呀=.=

  1. by lazy: 用于 延迟初始化
  2. 自定义委托,不如我想获取一个 用户id,那么他是在 本地数据库中的,那么我就可以
private val userId by UserIdDelegete()

UserIdDelegete中 定义了 user id 的获取和设置方法

写的不一定对哈,用的不多,也记不住

  1. butterknife好像有个kotlin 版本的 ,用于id查找,可以参考,很优秀

原理的话不太好写,但是可以借助于 kotlin byteCode 工具来看自动生成的代码,类委托的话大家自己百度吧,简单对比一下属性委托

//源文件

class A {
    private var name by Delegate()
}

class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, 这里委托了 ${property.name} 属性"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$thisRef${property.name} 属性赋值为 $value")
    }
}

ByteCode 工具decompile的java文件

public final class Delegate {
   @NotNull
   public final String getValue(@Nullable Object thisRef, @NotNull KProperty property) {
      //将属性传递过来,如果只有一个,直接写获取的逻辑就好
      Intrinsics.checkParameterIsNotNull(property, "property");
      return thisRef + ", 这里委托了 " + property.getName() + " 属性";
   }

   public final void setValue(@Nullable Object thisRef, @NotNull KProperty property, @NotNull String value) {
      Intrinsics.checkParameterIsNotNull(property, "property");
      Intrinsics.checkParameterIsNotNull(value, "value");
      String var4 = thisRef + " 的 " + property.getName() + " 属性赋值为 " + value;
      System.out.println(var4);
   }
}

public final class A {
   // $FF: synthetic field
  //虽然实际上我也不知道这个是啥意思,但是能大概猜出来啥意思,用于反射和属性定义,毕竟这个类实际上是没有 name:String 属性的
   static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Reflection.getOrCreateKotlinClass(A.class), "name", "getName()Ljava/lang/String;"))};
   //真正的类型是 Delegate的类型
   private final Delegate name$delegate = new Delegate();
   // get set 方法 是 String 类型
   private final String getName() {
     //调用委托的 getValue 方法
      return this.name$delegate.getValue(this, $$delegatedProperties[0]);
   }

   private final void setName(String var1) {
      this.name$delegate.setValue(this, $$delegatedProperties[0], var1);
   }
}

属性委托

有些常见的属性操作,我们可以通过委托方式,让它实现,例如:

  • lazy 延迟属性: 值只在第一次访问的时候计算
  • observable 可观察属性:属性发生改变时通知
  • map 集合: 将属性存在一个map集合里面

类委托

可以通过类委托来减少 extend
类委托的时,编译器回优使用自身重新函数,而不是委托对象的函数

interface Base{
fun print()
}

case BaseImpl(var x: Int):Base{

override fun print(){
print(x)
}

}
// Derived 的 print 实现会通过构造函数的b对象来完成
class Derived(b: base): Base by b
commented

类委托: class A: Base by BaseImp()  实现一个接口了正好有一个类可以使用

属性委托:委托的类需要实现 getValue和setValue 函数加上operator关键字

委托延迟: by lazy  ,lazy内只执行一次,后续只返回结果

委托工厂:主要需要实现ReadWriteProperty 接口

属性监听: Delegates.observable 无条件赋值 和Delegates.vetoable (有条件的赋值)