IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Kotlin 代理属性,面试题+笔记+项目实战 -> 正文阅读

[移动开发]Kotlin 代理属性,面试题+笔记+项目实战

val lazyValue: String by lazy {
    println("computed!")
    "Hello"
}

fun main() {
    println(lazyValue)
    println(lazyValue)
} 

默认情况下,惰性属性的评估是同步的:该值仅在一个线程中计算,所有线程将看到相同的值。如果不需要同步初始化委托,以便多个线程可以同时执行,则 LazyThreadSafetyMode.PUBLICATION 作为参数传递给 lazy() 函数。

如果您确定初始化将始终发生在与您使用该属性的线程相同的线程上,则可以使用 LazyThreadSafetyMode.NONE:它不会产生任何线程安全保证和相关开销。

lateinit 和 by lazy 的区别

我的理解是我们平时在项目中尽量少用 lateinit,因为很多东西我们是确定怎么初始化他的,这个时候只需要延迟初始化,使用 by lazy 就可以了。lateinit 我能想到的应用场景就是外部传了一个变量来初始化某个属性而且必不为空。由于 kotlinswift 一样,有着严格的检查,我们可以利用它来告诉编译器,我们要晚一点才能初始化它。这个也是在 swift 中不能优雅解决的一个点。

最近在看公司内部的项目,这个关键字被滥用了,看着贼难受。唉。。。

可观察属性

Delegates.observable() 接受两个参数:初始值和修改的闭包。 每次分配给属性时都会调用闭包(在执行分配之后)。它具有三个参数:被分配的属性、旧值和新值:

class User {
    var name: String by Delegates.observable("<no name>") {
        prop, old, new ->
        println("$old -> $new")
    }
}

fun main() {
    val user = User()
    user.name = "first"
    user.name = "second"
} 

如果您想拦截分配并否决它们,请使用 vetoable() 代替 observable()

委托给另一个属性

一个属性可以把他的 setter()getter() 代理给另一个属性。这种代理可以用于 top-levelclass 属性(成员或者扩展)。这种代理属性可以是:

  • 一个 top-level 属性
  • 同一个类中的成员属性或者扩展属性
  • 不同类中的成员属性或者扩展属性

像这种把一个属性委托给别一个属性的情况,要用 ::proper 的语法

var topLevelInt: Int = 0
class ClassWithDelegate(val anotherClassInt: Int)

class MyClass(var memberInt: Int, val anotherClassInstance: ClassWithDelegate) {
    var delegatedToMember: Int by this::memberInt
    var delegatedToTopLevel: Int by ::topLevelInt

    val delegatedToAnotherClass: Int by anotherClassInstance::anotherClassInt
}
var MyClass.extDelegated: Int by ::topLevelInt 

这个其实是很有用的。举个例子,如果我们想以向后兼容的方式重命名属性时:引入一个新的属性,用注释对旧属性进行 @Deprecated 注释,然后委托其实现。

class MyClass {
   var newName: Int = 0
   @Deprecated("Use 'newName' instead", ReplaceWith("newName"))
   var oldName: Int by this::newName
}
fun main() {
   val myClass = MyClass()
   // Notification: 'oldName: Int' is deprecated.
   // Use 'newName' instead
   myClass.oldName = 42
   println(myClass.newName) // 42
} 

上述两个例子是官方文档(1.5.10)提供的用法,老版本的 kotlin 是不支持的

属性代理

对于只读属性 val,委托应提供 getValue() 具有以下参数的运算符函数:

thisRef 必须是属性所有者的相同或超类型(对于扩展属性,它应该是被扩展的类型)。

property 必须是类型 KProperty<*> 或其超类型。

getValue() 必须返回与属性(或其子类型)相同的类型。

class Owner {
    val valResource: Resource by ResourceDelegate()
}

class ResourceDelegate {
    operator fun getValue(thisRef: Owner, property: KProperty<*>): Resource {
        return Resource()
    }
} 

对于可变属性 var,委托必须额外提供 setValue() 具有以下参数的运算符函数:

thisRef 必须是属性所有者的相同或超类型(对于扩展属性,它应该是被扩展的类型)。

property 必须是类型 KProperty<*> 或其超类型。

value 必须与属性(或其超类型)具有相同的类型。

getValue()/setValue() 函数可以作为委托类的成员函数或扩展函数提供。当您需要将属性委托给最初不提供这些功能的对象时,后者很方便。这两个函数都需要用 operator 关键字标记。

您可以将委托创建为匿名对象,而无需使用接口 ReadOnlyPropertyReadWritePropertyKotlin 标准库创建新类。它们提供了所需的方法:getValue()ReadOnlyProperty 中声明,ReadWriteProperty 扩展它并添加 setValue()。因此,您可以在需要传递 ReadOnlyProperty 的时候传递 ReadWriteProperty

fun resourceDelegate(): ReadWriteProperty<Any?, Int> =
    object : ReadWriteProperty<Any?, Int> {
        var curValue = 0
        override fun getValue(thisRef: Any?, property: KProperty<*>): Int = curValue
        override fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
            curValue = value
        }
    }

val readOnly: Int by resourceDelegate()  // ReadWriteProperty as val
var readWrite: Int by resourceDelegate() 

转换规则

Kotlin 编译器为每个委托属性生成一个辅助属性并委托给它。例如,为属性生成 prop 隐藏属性prop$delegate,访问器的代码简单地委托给这个附加属性:

class C {
    var prop: Type by MyDelegate()
}

// this code is generated by the compiler instead:
class C {
    private val prop$delegate = MyDelegate()
    var prop: Type
        get() = prop$delegate.getValue(this, this::prop)
        set(value: Type) = prop$delegate.setValue(this, this::prop, value)
} 

Kotlin 编译器 prop 在参数中提供了所有必要的信息:第一个参数 this 引用外部类的实例,C并且this::propKProperty 描述 prop 自身的类型的反射对象。

类代理

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-29 09:28:21  更:2021-08-29 09:28:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/31 6:11:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码