委托
- 委托是java不具备的功能,Kotlin的委托分为类委托和属性委托。
类委托
-
类委托是代理模式的应用,类委托的本质就是将本类需要实现的部分方法委托给其他对象,相当于借用其他方法作为自己的实现。当类重写委托对象所包含的方法时,kotlin优先使用该类自己实现的方法
-
类委托案例
interface Output { var type: String fun output(msg: String) } class DefaultOutput : Output { override var type: String = "默认输出类型" override fun output(msg: String) { for (i in 0..3) { println("打印4遍:${msg}") } } } //指定构造参数output作为委托对象,通过by关键字指定委托对象 class Printer(output: DefaultOutput) : Output by output //指定新建的对象作为委托对象,当类重写委托对象所包含的方法时 //kotlin优先使用该类自己实现的方法 class Printer2() : Output by DefaultOutput() { override fun output(msg: String) { for (i in 0..1) { println("打印2遍${msg}") } } } /** * 输出内容: * 打印4遍:哈哈哈 * 打印4遍:哈哈哈 * 打印4遍:哈哈哈 * 打印4遍:哈哈哈 * 默认输出类型 * 打印2遍哈哈哈 * 打印2遍哈哈哈 */ fun main() { val output = DefaultOutput() var printer = Printer(output) //其实就是调用委托对象的output printer.output("哈哈哈") println(printer.type) val printer2 = Printer2() printer2.output("哈哈哈") }
属性委托
-
属性委托: 属性委托可以将多个类的类似属性统一交给委托对象集中实现,这样就可以避免每个类都需要单独实现这些属性。对于指定了委托对象的属性,因为它的实现逻辑已经交给了委托对象处理,所以不能再为委托属性提供getter和setter方法。kotlin也不会为委托属性提供getter和setter的默认实现
-
属性的委托对象一定要提供一个getValue()方法和setValue()方法(val属性不需要)
-
getValue方法的要求
- thisRef: 该参数代表属性所属的对象,因此该参数的类型必须是属性所属对象的类型或者超类型
- property:该参数代表目标属性,该参数的类型必须是KProperty<*>或者超类型
- 返回值:该方法必须返回与目标属性相同的类型或者子类型
-
setValue方法的要求
- thisRef:与getValue作用一样
- property:与getValue作用一样
- newValue:该参数代表目标属性新设置的属性值,该参数的类型必须具有和目标属性相同的类型或超类型
-
代码案例
class NameDelegation { private var name = "jack" operator fun getValue(thisRef: PropertyDelegation, property: KProperty<*>): String { println("${thisRef}的${property.name}属性执行getter方法") return name; } operator fun setValue(thisRef: PropertyDelegation, property: KProperty<*>, newValue: String) { println("${thisRef}的${property.name}属性执行setter方法,传入参数的值:${newValue}") name = newValue } } class PropertyDelegation { //该属性的委托对象是NameDelegation var name: String by NameDelegation() } /** * cn.jannal.kotlin.delegation.PropertyDelegation@1fb3ebeb的name属性执行getter方法 * jack * cn.jannal.kotlin.delegation.PropertyDelegation@1fb3ebeb的name属性执行setter方法,传入参数的值:jannal * cn.jannal.kotlin.delegation.PropertyDelegation@1fb3ebeb的name属性执行getter方法 * jannal */ fun main() { var pd = PropertyDelegation() println(pd.name) pd.name = "jannal" println(pd.name) }
-
当程序读取PropertyDelegation对象的name属性时,实际上是执行NameDelegation对象所提供的getValue()方法。当程序对PropertyDelegation对象的name赋值时,实际上是调用NameDelegation对象所提供的setValue()方法。
-
Kotlin标准库在
kotlin.properties
下提供了ReadOnlyProperty
和ReadWriteProperty
两个接口。其中ReadOnlyProperty
接口定义了一个符合只读属性委托标准的getValue抽象方法。因此该接口的实现类可作为只读属性的委托对象。而ReadOnlyProperty
接口定义了符合读写属性委托标准的getValue()和setValue抽象方法。 -
属性委托给Map
//如果是可变属性,把只读Map转变为MutableMap即可 class Account(val map: Map<String, Any?>) { val name: String by map val password: String by map open override fun toString(): String { return "${this.name},${this.password}" } } fun main() { val account = Account(mapOf( "name" to "jannal", "password" to "admin" )) println("$account") }
-
使用委托实现属性的非空限制
//使用委托来实现属性的非空限制,name不能赋值为null,否则编译错误 var name: String by Delegates.notNull() //编译错误 //name = null
委托覆写冲突
-
委托覆写冲突
interface A { fun a() fun foo() } interface B { fun b() fun foo() } class A1 : A { override fun foo() = println("this is A foo!") override fun a() = println("this is a!") } class B1 : B { override fun foo() = println("this is B foo!") override fun b() = println("this is b!") } //class C : A by A1(), B by B1() { // override fun foo() { // //无法编译通过 // super<A>.foo() // } //} //可以使用如下方式 class C(private val a: A = A1()) : A by a, B by B1() { override fun foo() { a.foo() } }
lazy
-
lateinit
和lazy
是 Kotlin 中的两种不同的延迟初始化的实现.lateinit
只用于变量 var,而lazy
只用于常量 val(在第一次访问时进行计算) -
lazy 应用于单例模式(if-null-then-init-else-return),而且当且仅当变量被第一次调用的时候,委托方法才会执行
-
lazy()是一个函数, 可接受一个Lambda表达式作为参数,第一次调用将会执行 Lambda 表达式,以后调用该参数返回以前记住的结果.
1. lazy函数定义
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
2. 案例
fun main() {
val result: String by lazy {
println("jannal")
"Beijing"
}
/**
* jannal
* Beijing
* Beijing
*/
println(result)
println(result)
}
-
lazy属性的求值默认是线程安全的
//默认情况下,lazy属性的求值是同步的,等价以下方式 val sync: String by lazy(LazyThreadSafetyMode.SYNCHRONIZED, { println("lazy Value Synchronized 1 !") println("lazy Value Synchronized 2 !") "sync" }) println(sync) //多个线程同时执行 val async: String by lazy(LazyThreadSafetyMode.PUBLICATION, { println("lazy Value async 1 !") println("lazy Value async 2 !") println("lazy Value async 3 !") "async" }) println(async) //如果初始化是单线程的,可以使用NONE,性能最高 val singleThread: String by lazy(LazyThreadSafetyMode.NONE, { println("lazy Value single thread 1 !") println("lazy Value single thread 2 !") println("lazy Value single thread 3 !") "singleThread" }) println(singleThread)