1 类委托
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main(args: Array<String>) {
val b = BaseImpl(10)
Derived(b).print() // 输出 10
}
Derived 的超类型列表中的 by句表示b 将会在 Derived 中内部存储。 并且编译器将成转发给 b 的所有 Base 的法。
2 委托属性
class Example {
var p: String by Delegate()
}
语法是: val/var <属性名>: <类型> by <表达式>。
属性对应的 get()(和 set() )会被委托给表达式的getValue() 和 setValue()。
第一个参数是 p 所在对象的引用、第二个参数保存了对 p属性自身的描述;
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name} in $thisRef.'")
}
}
对于只读属性(即 val 声明的),委托必须提供名为 getValue 的函数,该函数接受以下参数:
thisRef 必须与属性所有者类型(对于扩展属性指被扩展的类型)相同或者是它的超类型。
property 必须是类型 KProperty<*>或其超类型。
这个函数必须返回与属性相同的类型(或其类型)。
对于可变属性(即 var 声明的),委托必须额外提供 setValue 的函数,该函数接受以下参数:
thisRef 同 getValue() ;
property 同 getValue() ;
new value 必须和属性同类型或者是它的超类型。
getValue() 或/和 setValue() 函数可以通过委托类的成员函数提供或者由扩展函数提供。 两函数都需要 operator 关键字来标记。
委托类可以实现包含所需 operator 方法的 ReadOnlyProperty 或 ReadWriteProperty。
这俩接口是在 Kotlin 标准库中声明的:
interface ReadOnlyProperty<in R, out T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
}
interface ReadWriteProperty<in R, T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}
3 延迟属性 Lazy
val lazyValue: String by lazy {
"Hello"
}
延迟加载属性(lazy property): 属性值只在初次访问时才会计算;
get()会执行lambda表达式并记录结果,后续的get方法将只返回结果。
var类型属性不能设置为延迟加载属性,因为在lazy中并没有setValue(…)方法。
lazy操作符是线程安全的。如果在不考虑多线程问题或者想提高更多的性能,也可以使
用 lazy(LazyThreadSafeMode.NONE){ … } 。
在LazyThreadSafetyMode中声明了几种,[Lazy]实例在多个线程之间同步访问的形式:
SYNCHRONIZED:锁定,用于确保只有一个线程可以初始化[Lazy]实例。
PUBLICATION:初始化函数可以在并发访问未初始化的[Lazy]实例值时调用几次,,但只有第一个返回的值将被用作[Lazy]实例的值。
NONE:没有锁用于同步对[Lazy]实例值的访问; 如果从多个线程访问实例,是线程不安全的。此模式应仅在高性能至关重要,并且[Lazy]实例被保证永远不会从多个线程初始化时使用。
class App : Application() {
val database: SQLiteOpenHelper by lazy {
MyDatabaseHelper(applicationContext)
}
override fun onCreate() {
super.onCreate()
val db = database.writableDatabase
}
}
4 可观察属性(Observable)
Delegates.observable() 函数接受两个参数:
第一个是初始化值,
第二个是属性值变化事件的响应器(handler).
这种形式的委托,采用了观察者模式,其会检测可观察属性的变化,当被观察属性的setter()方法被调用的时候,响应器(handler)都会被调用(在属性赋值处理完成之后)并自动执行执行的lambda表达式,同时响应器会收到三个参数:被赋值的属性, 赋值前的旧属性值, 以及赋值后的新属性值。
class ViewModel(val db: MyDatabase) {
var myProperty by Delegates.observable("") {
d, old, new ->
db.saveChanges(this, new)
}
}
5 Map中映射值
在像解析 JSON 或者做其他“动态”事情中。把map映射到属性
import kotlin.properties.getValue
class Configuration(map: Map<String, Any?>) {
val width: Int by map
val height: Int by map
val dp: Int by map
val deviceName: String by map
}
conf = Configuration(mapOf(
"width" to 1080,
"height" to 720,
"dp" to 240,
"deviceName" to "mydevice"
))
6 局部委托属性
你可以将局部变量声明为委托属性。
memoizedFoo 只有someCondition满足条件,第一调用才会初始化
fun example(computeFoo: () -> Foo) {
val memoizedFoo by lazy(computeFoo)
if (someCondition && memoizedFoo.isValid()) {
memoizedFoo.doSomething()
}
}