• 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

  • 相关阅读:
    docker容器日志收集方案(方案四,目前使用的方案)
    docker容器日志收集方案(方案三 filebeat+journald本地日志收集)
    docker容器日志收集方案(方案二 filebeat+syslog本地日志收集)
    docker容器日志收集方案(方案一 filebeat+本地日志收集)
    企业业务数据处理用“work”还是“MQ”
    spring cloud 实践之hystrix注意事项
    微服务架构理论-扩展立方体篇
    C# asp.net PhoneGap html5
    C# Where
    网站分布式开发简介
  • 原文地址:https://www.cnblogs.com/strongmore/p/16323825.html
Copyright © 2020-2023  润新知