kotlin委托属性
委托属性kotlin中除了可以委托类外,还可以委托属性。委托属性语法如下:class Person {var name: String by Delegate()}而Delegate类需要实现ReadWriteProperty接口,ReadWriteProperty接口的声明如下:public interface ReadWriteProperty<in T, V> : ReadOnl
委托属性
kotlin中除了可以委托类外,还可以委托属性。
委托属性
语法如下:
class Person {
var name: String by Delegate()
}
而Delegate类需要实现ReadWriteProperty接口,ReadWriteProperty接口的声明如下:
public interface ReadWriteProperty<in T, V> : ReadOnlyProperty<T, V> {
public override operator fun getValue(thisRef: T, property: KProperty<*>): V
public operator fun setValue(thisRef: T, property: KProperty<*>, value: V)
}
如果是只读属性(val属性),那么需要实现ReadOnlyProperty接口,ReadOnlyProperty接口的声明如下:
public fun interface ReadOnlyProperty<in T, out V> {
public operator fun getValue(thisRef: T, property: KProperty<*>): V
}
当然Delegate类不一定要实现ReadWriteProperty和ReadOnlyProperty接口,只需要保持方法的签名一直就行。
Delegate类的代码如下:
class Delegate : ReadWriteProperty<Person, String> {
override fun setValue(thisRef: Person, property: KProperty<*>, value: String) {
println("${thisRef}, ${property.name}, $value")
}
override fun getValue(thisRef: Person, property: KProperty<*>): String {
println("${thisRef}, ${property.name}")
return "welcome"
}
}
这样对Person.name的读操作就会委托给Delegate.getValue(),对Person.name的写操作就会委托给Delegate.setValue()。
延迟属性
延迟属性会在第一次被访问时才会计算,然后缓存起来供后续调用使用。
val lazyValue: String by lazy {
println("invoked")
"hello"
}
fun main() {
println(lazyValue)
println(lazyValue)
}
lazy关键字其底层其实是一个函数,源代码如下,还有个重载的方法:
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
public actual fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
when (mode) {
LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer)
LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer)
LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
}
mode参数有下面三种取值:
- LazyThreadSafetyMode.SYNCHRONIZED:默认情况下,延迟属性的计算是同步的,值只会在一个线程中得到计算,所有的线程都会使用相同的结果。
- LazyThreadSafetyMode.PUBLICATION:如果不需要初始化延时属性的同步,这样多个线程就可以同时执行。
- LazyThreadSafetyMode.NONE:如果确定初始化操作只会在一个线程中执行,这样就能减少线程安全方面的开销。
非空属性
notNull适用于那些无法在初始化阶段就确定属性值的场合。
class A {
var name by Delegates.notNull<String>()
}
可观测属性
可观测属性可以在属性的值发生变化时进行监听。
Delegates.observable在值发生变化后触发:
class B {
var name by Delegates.observable("hello") { property, oldValue, newValue ->
println("property: ${property.name}, oldValue: $oldValue, newValue: $newValue")
}
}
Delegates.observable在值发生变化前触发,返回true就会设置属性,返回false不会设置属性:
class C {
var name by Delegates.vetoable("hi") { property, oldValue, newValue ->
println("property: ${property.name}, oldValue: $oldValue, newValue: $newValue")
true
}
}
map属性
通常在json中,我们将属性和值存在map中,可以将map作为属性的委托。
map只读属性:
class D(map: Map<String, Any>) {
val name: String by map
val age: Int by map
}
fun main() {
var map = mapOf(
"name" to "morris",
"age" to 20
)
var d = D(map)
println(d.name) // morris
println(d.age) // 20
}
map读写属性:
class E(map: MutableMap<String, Any>) {
var name: String by map
var age: Int by map
}
fun main() {
var mutableMap: MutableMap<String, Any> = mutableMapOf(
"name" to "morris",
"age" to 20
)
var e = E(mutableMap)
println(e.name) // morris
println(e.age) // 20
mutableMap["name"] = "Marry"
println(e.name) // Marry
}
注意对map中属性的修改会体现到对象的属性上。
委托另一个属性
class F(name: String) {
var newName: String = name
var oldName: String by this::newName
}
委托的属性可以是以下三种:
- 一个顶级属性(不包含在类中)
- 同一个类中的成员或者扩展属性
- 其他类中的成员或者扩展属性
转换规则
kotlin编译器为每个委托属性提供了一个辅助的属性,对原属性的访问都会委托给这个辅助属性。例如对属性prop来说,kotlin编译器会生成辅助属性propdelegate,对prop的访问都会委托给propdelegate,对prop的访问都会委托给propdelegate,对prop的访问都会委托给propdelegate。
提供委托
通过定义providerDelegate operator,我们可以扩展委托的创建逻辑过程,如果对象定义了providerDelegate方法,那么该方法就会用来创建属性委托实例。
package com.morris.kotlin.delegationpropertiest
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
class PeopleDelegate: ReadOnlyProperty<People, String> {
override fun getValue(thisRef: People, property: KProperty<*>): String {
return "morris"
}
}
class PeopleLauch {
operator fun provideDelegate(thisRef: People,prop: KProperty<*>): ReadOnlyProperty<People, String> {
when(prop.name) {
"name","address" -> return PeopleDelegate()
else -> throw Exception("error property")
}
}
}
class People {
val name : String by PeopleLauch()
val address: String by PeopleLauch()
}
fun main() {
var people = People()
println(people.name) // morris
}
更多推荐

所有评论(0)