委托 by 操作符

属性委托给属性

使用 by:: 操作符,代表调用系统内置的方法。

读:getVaule

写:setValue

共享同一个数据。

/**
 * 属性委托给属性
 * by:: 系统内置的方法,非自定义的
 * 共享同一个数据
 */
var num:Float = 9999.0f

/**
 * newNum属性委托使用num属性的set和get
 * by:: 系统内置的方法,非自定义的
 */
var newNum :Float by:: num

fun main(args: Array<String>) {
    println("改变newNum的值,num的值也会改变")
    newNum = 0.5f
    println(newNum)
    println(num)

    println("改变num的值,newum的值也会改变")
    num = 1.5f
    println(newNum)
    println(num)
}

属性委托给类

继承委托(将继承接口的实现委托给构造函数的参数)

可以在实例化时由传入的参数决定使用哪个类实现接口。

package agency

/**
 * 属性委托给类
 * 第一种:继承时将接口的实现委托给构造函数的参数
 */
interface DB{
    fun open();
}

class MyDB:DB{
   override fun open(){
       print("我是MyDB")
   }
}

class SqlDB:DB{
    override fun open(){
        print("我是SqlDB")
    }
}

/**
 * CreateDB类将DB接口的实现委托给了构造函数中的参数db来实现。
 */
class CreateDB(db:DB):DB by db{

}

fun main(args: Array<String>) {
    //具体使用,在创建的时候传入参数。
    var db = MyDB()
    var createDB = CreateDB(db)
    createDB.open()
}

自定义委托类

自定义委托类有两种方法,一种是自行实现getValue和setValue方法,一种是通过实现ReadWriteProperty/ReadOnlyProperty接口。

两者原理一致。

属性通过by操作符委托给类。

在读属性的时候访问委托类的getValue函数,在写属性的时候访问委托类的setValue函数。

package agency

import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

/**
 * 属性委托给类
 * 第二种:自定义委托类
 */
class TestAgency{
    /**
     * 将str的数据委托给CustomAgency类的实例
     * var 可读可写 被委托类需要实现setVaule和getVaule
     */
    var str:String by CustomAgencyString()

    var str02:String by CustomAgencyString02()

    /**
     * 将finalNum的数据委托给CustomInt类的实例
     * val 可读不可写 被委托类需要只实现getVaule即可
     */
    val finalNum:Int by CustomAgencyInt()

    val finalNum02:Int by CustomAgencyInt02()
}

/**
 * 第一种:自定义委托类,自己实现getValue和setValue方法
 */
class CustomAgencyString{
    var strData:String = "我是CustomAgency"

    /**
     * 自定义委托实现
     * 第一个参数是委托属性所在的类 TestAgency
     * 第二个参数是 KProperty<*> 固定
     * 返回值类型是委托属性的类型
     */
    operator fun getValue(any: Any, property: KProperty<*>): String {
        return strData
    }

    /**
     * 自定义委托实现
     * 第一个参数是委托属性所在的类 TestAgency
     * 第二个参数是 KProperty<*> 固定
     * 第三个参数是 要设置的数据
     */
    operator fun setValue(any: Any, property: KProperty<*>, s: String) {
        strData = s
    }
}

/**
 * 第二种:自定义委托类,继承ReadWriteProperty接口
 * ReadWriteProperty接口有两个泛型,
 * 第一个是委托属性所在的类及其父类(TestAgency/Any)
 * 第二个是委托属性的类型
 *
 * 好处:getValue和setValue方法通过继承ReadWriteProperty接口实现
 */
class CustomAgencyString02:ReadWriteProperty<Any,String>{
    var strData:String = "我是CustomAgency02"
    override fun getValue(thisRef: Any, property: KProperty<*>): String {
        return strData
    }

    override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
        strData = value
    }

}

/**
 * 第一种:自定义委托类
 */
class CustomAgencyInt {
    operator fun getValue(testAgency: TestAgency, property: KProperty<*>): Int {
        return 10
    }
}

/**
 * 第二种:自定义委托类 通过继承ReadOnlyProperty实现
 */
class CustomAgencyInt02:ReadOnlyProperty<Any,Int> {
    override fun getValue(thisRef: Any, property: KProperty<*>): Int {
        return 20
    }

}

fun main() {
    var testAgency = TestAgency()

    println(testAgency.str)
    testAgency.str = "我是CustomAgency修改过后的数据"
    println(testAgency.str)
    println(testAgency.str02)

    println()
    println(testAgency.finalNum)
    println(testAgency.finalNum02)
}

by lazy (委托+懒加载)-特殊的委托类

by lazy共同使用的时候。

by调用的是Lazy.kt的getValue函数

getValue函数返回数据了value。

value是?

value是Lazy接口中的属性,那实现类是谁?

时使用过lazy函数返回的SynchronizedLazyImpl类的实例。

lazy函数是一个参数是函数的函数。

返回SynchronizedLazyImpl类,SynchronizedLazyImpl类实现了Lazy接口

by lazy 实际使用的是SynchronizedLazyImpl类中的value,value是lazy操作符传入的方法的返回值。

package agency

/**
 * 属性委托给lazy函数 = 其本质还是委托给了类
 * lazy函数返回一个类
 *
 * by lazy  委托+懒加载  在使用的时候才加载。
 */
fun requestNum():Float{
    println("requestNum开始执行")
    return 0.5f
}
/**
 * 普通调用函数
 * 会在main() 之前运行,加载的时候就执行了requestNum()
 * requestNum()在加载requestNum变量时执行了一次。
 * main()中使用requestNum时不再执行。
 * 同java
 */
var requestNum = requestNum()


/**
 * by lazy
 *
 * by 委托
 *
 * lazy是一个函数,一个参数是函数的函数。
 *
 * 效果:
 * 在使用requestRetrun的时候才执行,且只执行一次,
 * 使用第二次及以后,只会输出结果
 * 在使用变量的时候才执行方法
 */
val requestRetrun:String by lazy{ requestData() }

fun requestData():String{
    println("requestData开始执行")
    Thread.sleep(1000)
    return "requestData 结果"
}


fun main() {
    println("开始运行")
    println(requestNum)
    println(requestNum)
    Thread.sleep(3000)

    println(requestRetrun)
    println(requestRetrun)
}

提供者委托

使用provideDelegate方法重载by操作符。

注意provideDelegate方法名不能写错。

package agency

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

/**
 * 提供者委托
 * 功能:
 * 可以根据情况选择不同的代理类,重载了by操作符
 */

/**
 * provideDelegate放在类的外边,是类的扩展函数,和放在类的内部效果一样
 */
operator fun AgencyProvideDelegate.provideDelegate(any: Any, prop: KProperty<*>): ReadWriteProperty<Any, String> {
    //如果委托属性的名称 = str,返回AgencyClass01,如果不等于str,返回AgencyClass02
    if (prop.name.equals("str")) {
        return AgencyClass01();
    } else {
        return AgencyClass02();
    }
}

class AgencyProvideDelegate {
    /**
     * provideDelegate重载by操作符
     * 参数:
     * 1.委托属性所在类或其父类
     * 2.固定KProperty<*>,委托属性的参数
     * 返回类型:ReadWriteProperty<Any,String>
     */
//    operator fun provideDelegate(any: Any,prop:KProperty<*>):ReadWriteProperty<Any,String>{
//        //如果委托属性的名称 = str,返回AgencyClass01,如果不等于str,返回AgencyClass02
//        if(prop.name.equals("str")){
//            return AgencyClass01();
//        }else{
//            return AgencyClass02();
//        }
//    }

}

class AgencyClass01 : ReadWriteProperty<Any, String> {
    var str = "AgencyClass01"
    override fun getValue(thisRef: Any, property: KProperty<*>): String {
        return str
    }

    override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
        str = value
    }
}

class AgencyClass02 : ReadWriteProperty<Any, String> {
    var str = "AgencyClass02"
    override fun getValue(thisRef: Any, property: KProperty<*>): String {
        return str
    }

    override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
        str = value
    }
}

class Agency01 {
    /**
     * 实际委托类是AgencyClass01
     * by操作符执行的AgencyProvideDelegate类的provideDelegate方法
     */
    var str: String by AgencyProvideDelegate()

    /**
     * 实际委托类是AgencyClass02
     * by操作符执行的AgencyProvideDelegate类的provideDelegate方法
     */
    var str02: String by AgencyProvideDelegate()//AgencyClass02代理
}

fun main() {
    var agency01 = Agency01()
    println(agency01.str)
    println(agency01.str02)
}

 

实际案例-属性与控件双向绑定

属性与控件的双向绑定。

是Jetpack DataBinding的原理。

/**
 * 给TextView类扩展了provideDelegate方法,用于重载by操作符
 * 功能:
 * 将str属性委托给textview控件的text属性
 * 实现了str属性和TextView控件的双向绑定,即修改str属性会修改textview控件的text属性,修改textview控件的text属性会修改str属性
 */
operator fun TextView.provideDelegate (any: Any?,prop: KProperty<*>):ReadWriteProperty<Any?,String?> {
    return object:ReadWriteProperty<Any?,String?>{
        override fun getValue(thisRef: Any?, property: KProperty<*>): String? {
            return text.toString()
        }

        override fun setValue(thisRef: Any?, property: KProperty<*>, value: String?) {
            text = value
        }
    }
}

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        var textview: TextView = findViewById(R.id.textview)

        //str属性委托给textview控件
        var str:String? by textview

        str = "我是通过str变量修改的"

        textview.text = "我是通过textview控件修改的"
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值