• Kotlin学习笔记(八)by的作用,属性委托和类的委托,和Lazy的关系


    标题上写了三个话题, 它们是什么关系呢?by关键字用于属性委托和类委托,而Lazy是属性委托的一种优秀应用。

    • 属性委托

    属性的赋值来自定义好的委托类。使用更加简单,只要用关键字by指定委托类,就可以在运行时赋值了。属性委托也是约定的功能之一。

    看下面的代码:目的是给MainActivity的ViewBinding根实例赋值。

    1. class MainActivity {
    2. override val viewDataBinding: ActivityMainBinding by ActivityDataBindingDelegate(R.layout.activity_main)
    3. }

     viewDataBinging的赋值来自ActivityDataBindingDelegate代理类getValue()函数的返回结果。

    1. class ActivityDataBindingDelegate<out VD : ViewDataBinding>(@LayoutRes private val layoutRes: Int) :
    2. ReadOnlyProperty {
    3. private var binding: VD? = null
    4. override fun getValue(thisRef: Activity, property: KProperty<*>): VD =
    5. binding ?: DataBindingUtil.setContentView(thisRef, layoutRes)
    6. .also { binding = it }
    7. }

    而ActivityDataBindingDelegate实现了接口ReadOnlyProperty的getValue, getValue的函数签名是固定格式,而且我们知道约定要有operator修饰。

    属性委托也有成对的get/set模式, 也就是接口ReadWriteProperty。

    1. public fun interface ReadOnlyProperty {
    2. public operator fun getValue(thisRef: T, property: KProperty<*>): V
    3. }
    4. public interface ReadWriteProperty<in T, V> : ReadOnlyProperty<T, V> {
    5. public override operator fun getValue(thisRef: T, property: KProperty<*>): V
    6. public operator fun setValue(thisRef: T, property: KProperty<*>, value: V)
    7. }

    当然,不是说一定要实现这两个接口。属性委托限制的只是get/set的定义。

    也可以这样:

    1. class TestDelegate {
    2. operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
    3. return "alan"
    4. }
    5. operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
    6. println("alan"+value)
    7. }
    8. }
    9. fun main() {
    10. var testDelegate by TestDelegate()
    11. // 使用testDelegate ,这时候会去调用TestDelegate的getValue方法
    12. println(testDelegate )
    13. // 设置testDelegate 的值,这时候去会调用setValue方法
    14. demoString = "gong"// 输出:"alan gong"
    15. }
    • Lazy懒加载

    它的意思是参数只会初始化一次,第一调用时会返回第一次初始化的值。

    而且第一次使用是属性值初始化的时候,不是说在类的其他方法里第一次调用的时候。

    1. class TestLazy() {
    2. private val name by lazy {
    3. "alan"
    4. }
    5. }

    lazy是个函数,返回实现Lazy接口的对象实例。默认是线程安全的SynchronizedLazyImpl。

    按道理Lazy实现类SynchronizedLazyImpl,应该有属性委托的getValue()函数,但是看源码是没有的,但是在编译时生成的。不知道是为什么。但是有一个get()方法,作用是初始化值,以及处理多线程同步问题。

    1. private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy, Serializable {
    2. private var initializer: (() -> T)? = initializer
    3. @Volatile private var _value: Any? = UNINITIALIZED_VALUE
    4. // final field is required to enable safe publication of constructed instance
    5. private val lock = lock ?: this
    6. override val value: T
    7. get() {
    8. val _v1 = _value
    9. if (_v1 !== UNINITIALIZED_VALUE) {
    10. @Suppress("UNCHECKED_CAST")
    11. return _v1 as T
    12. }
    13. return synchronized(lock) {
    14. val _v2 = _value
    15. if (_v2 !== UNINITIALIZED_VALUE) {
    16. @Suppress("UNCHECKED_CAST") (_v2 as T)
    17. } else {
    18. val typedValue = initializer!!()
    19. _value = typedValue
    20. initializer = null
    21. typedValue
    22. }
    23. }
    24. }
    25. override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
    26. override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
    27. private fun writeReplace(): Any = InitializedLazyImpl(value)
    28. }
    • 类委托

    这个就是设计模式中的代理模式。只是比java更简便了。有一点要记住,代理方法都必须是事先定义好的接口。

    1. class ByTest {
    2. // 定义一个代理接口,和一个代理方法 show(), 这个接口必须定义。
    3. interface Proxy{
    4. fun show()
    5. }
    6. // 实现类实现 Proxy接口, 并实现 show 方法
    7. open class ProxyImpl : Proxy{
    8. override fun show() {
    9. Log.e("ProxyImpl ::show()")
    10. }
    11. }
    12. // 定义代理类实现 Proxy接口, 构造函数参数是一个 Proxy对象
    13. // by 后跟 Proxy对象, 不需要再实现 show()
    14. class NeedProxy(proxy: Proxy) : Proxy by proxy{
    15. fun showOther() {
    16. Log.e("NeedProxy::showOther()")
    17. }
    18. }
    19. // main 方法
    20. fun mainGo() {
    21. val base = ProxyImpl ()
    22. NeedProxy(base).show()
    23. NeedProxy(base).showOther()
    24. }
    25. }
    26. 输出:
    27. ProxyImpl::show()
    28. NeedProxy::showOther()

  • 相关阅读:
    [笔记]ceil()
    【Flutter】 Flutter Material Design 3 组件使用示例 1 FAB/Icon button/Segmented button/Badge/Progress
    CocosCreator3.8研究笔记(十三)CocosCreator 音频资源理解
    创作一款表情包生成微信小程序:功能详解与用户体验优化
    Springframework之ResponseBodyAdvice——响应拦截处理
    ELK集群部署
    pycharm使用运行Docker容器的python解释器
    Map介绍
    Webpack入门:常用loader和plugin配置
    Python的GIL存在的情况下,是否还有必要添加线程锁。
  • 原文地址:https://blog.csdn.net/zjuter/article/details/126181829