Kotlin学习之委托

类委托

复制fun main(args: Array<String>) {
    SingerAgent(Singer()).sing()
}
interface Singable {
    fun sing()
}
//歌手,被委托人
class Singer : Singable {
    override fun sing() {
        println("sing")
    }
}
//歌手经纪人,将唱歌这件事委托给歌手
class SingerAgent(singer: Singer) : Singable by singer

类委托,编译器会生成接口的方法实现,直接调用委托者的方法。反编译结果为

点击查看代码
复制public final class SingerAgent implements Singable {
   // $FF: synthetic field
   private final Singer $$delegate_0;

   public SingerAgent(@NotNull Singer singer) {
      Intrinsics.checkParameterIsNotNull(singer, "singer");
      super();
      this.$$delegate_0 = singer;
   }

   public void sing() {
      this.$$delegate_0.sing();
   }
}

属性委托

复制import kotlin.reflect.KProperty

fun main(args: Array<String>) {
    val person = Person()
    person.username = "lisi2"
    println(person.username)
}
class MyDelegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("委托对象:${thisRef},属性:${property.name}")
        return "lisi"
    }
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("委托对象:${thisRef},属性:${property.name},值:${value}")
    }
}
class Person {
    var username: String by MyDelegate()
}

将Person类的username属性的getter和setter委托给MyDelegate类。反编译结果为

点击查看代码
复制public final class MyDelegate {
   @NotNull
   public final String getValue(@Nullable Object thisRef, @NotNull KProperty property) {
      Intrinsics.checkParameterIsNotNull(property, "property");
      String var3 = "委托对象:" + thisRef + ",属性:" + property.getName();
      System.out.println(var3);
      return "lisi";
   }

   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 Person {
   // $FF: synthetic field
   static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Reflection.getOrCreateKotlinClass(Person.class), "username", "getUsername()Ljava/lang/String;"))};
   @NotNull
   private final MyDelegate username$delegate = new MyDelegate();

   @NotNull
   public final String getUsername() {
      return this.username$delegate.getValue(this, $$delegatedProperties[0]);
   }

   public final void setUsername(@NotNull String var1) {
      Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
      this.username$delegate.setValue(this, $$delegatedProperties[0], var1);
   }
}
复制import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

fun main(args: Array<String>) {
    val person = Person()
    person.username = "lisi2"
    println(person.username)
}
class MyDelegate : ReadWriteProperty<Any?, String> {
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("set value: $value")
    }
    override fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("get value")
        return "lisi"
    }
}
class Person {
    var username: String by MyDelegate()
}

kotlin中提供了两个接口ReadWriteProperty(可读可写)和ReadOnlyProperty(只读),我们定义的委托类只需要实现这两个接口就可以了,让编译器来保证我们方法签名的有效性。

标准委托

kotlin标准库中内置了很多工厂方法来实现属性的委托。

延迟属性

复制fun main(args: Array<String>) {
    val age by lazy {
        println("delegate") //第一次调用时执行
        30
    }
    println(age)
    println(age)
}

输出结果为

复制delegate
30
30

基本原理就是: 内部定义一个属性,保存初始化之后的值,下次直接取这个值。

非空属性

复制import kotlin.properties.Delegates

fun main(args: Array<String>) {
    val person = Person()
    person.age = 23
    //访问前必须先赋值,不然抛异常
    println(person.age)
}
class Person {
    var username: String = ""
    var age: Int by Delegates.notNull()
}

正常属性我们必须要赋一个初值,如username,但有些情况我们在初始化阶段不能确定初始值,这种情况可以使用非空属性委托,在使用前赋值。

可观测属性

复制import kotlin.properties.Delegates

fun main(args: Array<String>) {
    val person = Person()
    person.age = 23
    person.age = 24
    person.age = 25
    println(person.age)
}
class Person {
    var age: Int by Delegates.observable(20) { property, oldValue, newValue ->
        println("${property.name},oldValue:$oldValue,newValue:$newValue")
    }
}

相当于对一个属性添加事件监听器,每次值变化时都会触发(修改后)。

map委托

复制fun main(args: Array<String>) {
    //定义一个map
    val map = mapOf(
        "username" to "lisi",
        "age" to 20
    )
    val person = Person(map)
    println(person)//lisi,20
}
class Person(map: Map<String, Any>) {
    val username: String by map
    val age: Int by map

    override fun toString(): String {
        return "$username,$age"
    }
}

将属性委托给map对象,属性名称需要和map的key一致。

复制fun main(args: Array<String>) {
    //定义一个可变map
    val map = mutableMapOf(
        "username" to "lisi",
        "age" to 20
    )
    val person = Person(map)
    person.age = 23
    println(map)//{username=lisi, age=23}
}
class Person(map: MutableMap<String, Any>) {
    var username: String by map
    var age: Int by map

    override fun toString(): String {
        return "$username,$age"
    }
}

如果属性需要定义为可变的,map需要为MutableMap类型,表示可变map。

提供委托

复制fun main(args: Array<String>) {
    val person = Person()
    person.username = "lisi2"
    println(person.username)
}
//具体的委托类
class MyDelegate : ReadWriteProperty<Any?, String> {
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("set value: $value")
    }
    override fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("get value")
        return "lisi"
    }
}
//委托提供者
class MyLauncher {
    operator fun provideDelegate(
        thisRef: Person,
        property: KProperty<*>
    ): ReadWriteProperty<Person, String> {
        return when (property.name) {
            "username" -> MyDelegate()
            else -> throw Exception("invalid name")
        }
    }
}
class Person {
    var username: String by MyLauncher()
    var username2: String by MyLauncher()
}

委托提供者,也可以看做委托工厂,根据不同条件返回不同的委托类,provideDelegate()参数必须和委托者的getValue()参数一致。

参考

Kotlin 教程
学习 Kotlin

posted @   strongmore  阅读(136)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
历史上的今天:
2021-06-01 java处理emoji表情
点击右上角即可分享
微信分享提示