Kotlin 委托(1)类委托、变量委托注意事项
1.官方文档
英文:
https://kotlinlang.org/docs/reference/delegation.html
https://kotlinlang.org/docs/reference/delegated-properties.html
中文:
https://www.kotlincn.net/docs/reference/delegation.html
https://www.kotlincn.net/docs/reference/delegated-properties.html
2.委托作用
用来实现代理/委托模式,可以在不修改原来代码及软件结构的情况下,对原有功能扩展或者修改。也可以在设计时直接使用委托模式方便扩展。
3.类委托
3.1 示例
1 interface __base1__ { fun f2() } 2 3 class base1Impl : __base1__ { 4 override fun f2() { 5 Log.e(TAG_DELEGATE,"base1Impl.f2()") 6 } 7 } 8 9 class delegate1(var impl : __base1__) : __base1__ by impl 10 11 12 fun delegate_test1(){ 13 14 Log.e(TAG_DELEGATE,"====================================== delegate_test_ 1 ") 15 16 var impl = base1Impl() 17 var delegate1 = delegate1(impl) 18 19 delegate1.f2() 20 21 var d2 = delegate1(object : __base1__{ 22 override fun f2() { 23 Log.e(TAG_DELEGATE,"delegate1.companion.impl.f2()") 24 } 25 }) 26 27 d2.f2() 28 }
结果
2019-09-13 09:46:04.165 25360-25360/com.example.kotlin E/delegate: ====================================== delegate_test_ 1
2019-09-13 09:46:04.166 25360-25360/com.example.kotlin E/delegate: base1Impl.f2()
2019-09-13 09:46:04.166 25360-25360/com.example.kotlin E/delegate: delegate1.companion.impl.f2()
其中:
- __base1__是接口,
- base1Impl 是__base1__的实现
- delegate1 是个委托,它在声明实现接口__base1__,但是并没有实现任何函数。是把它交给它的一个成员impl处理。这个impl就是base1Impl
- kotlin中使用关键字 by 声明委托。如下:
class delegate1(var impl : __base1__) : __base1__ by impl
3.2 接口能被委托,类不可以
1 open class deleagte_base2 2 open class delegate_sub1 : deleagte_base2() 3 class delegate1(base1 : deleagte_base2) : deleagte_base2 by base1 //error 只有接口能被委托,类不可以 4 5 abstract class AB1{ 6 abstract fun f1() 7 } 8 class D2 (var ab : AB1) : AB1 by ab //error,抽象类也不可以委托。
结果: 第3、8 行编译不过。
3.3 不要重写委托接口的方法
不要重写委托接口的方法,否则调用的是重写版本的,不是委托对象的。
1 interface __I3__ { fun f3() } 2 3 class I3Impl : __I3__{ 4 override fun f3() { 5 Log.e(TAG_DELEGATE,"I3Impl.f3()") 6 } 7 } 8 9 class delegate3(i3 : __I3__) : __I3__ by i3 { 10 override fun f3() { //不要重写委托类的方法,否则调用的是重写的,不是委托的。 11 Log.e(TAG_DELEGATE,"delegate3.f3()") 12 } 13 } 14 15 fun delegate_test3(){ 16 17 Log.e(TAG_DELEGATE,"====================================== delegate_test_ 3 ") 18 19 var im3 = I3Impl() 20 21 var delegate3 = delegate3(im3) 22 23 delegate3.f3() 24 25 }
结果
2019-09-13 10:55:35.772 27606-27606/com.example.kotlin E/delegate: ====================================== delegate_test_ 3
2019-09-13 10:55:35.772 27606-27606/com.example.kotlin E/delegate: delegate3.f3()
delegate3 中的f3被执行,并不是 I3Impl 的f3 被执行。
4.变量委托
成员变量、全局变量、局部变量 的管理都可以委托给其它特定对象。
4.1 kotlin语言包里自带的变量委托
委托 | 作用 |
lazy |
不可变量(val)的延迟初始化 |
observable |
观察变量的变化 |
vetoable | 观察变量的变化,且在改值时有否定权 |
notNull | 变量是否为空,为空是不可使用。 |
map | 变量委托给一个map管理 |
4.2 自带变量委托示例
1 //成员变量使用委托属性 2 class delegate4{ 3 4 val name : String by lazy(mode = LazyThreadSafetyMode.NONE){ 5 //mode = LazyThreadSafetyMode.PUBLICATION 表示关闭同步锁,默认开启同步锁的 6 Log.e(TAG_DELEGATE,"lazy called ") 7 "lazy" 8 } 9 10 var value : Int by Delegates.observable(initialValue = 0){ 11 prop,old,new -> 12 Log.e(TAG_DELEGATE,"${prop.name} onChanged : old = $old,new = $new") 13 } 14 15 var count : Int by Delegates.vetoable(initialValue = 8){ 16 prop,old,new -> 17 Log.e(TAG_DELEGATE,"${prop.name} onChanged : old = $old,new = $new ") 18 false //return false 表示不接受修改,本次修改被否决 19 } 20 21 var str : String by Delegates.notNull() //在未初始化前使用,IllegalStateException。 22 23 } 24 25 fun delegate_test4(){ 26 Log.e(TAG_DELEGATE,"====================================== delegate_test_ 4 ") 27 28 var d4 = delegate4() 29 30 d4.value = 99 31 32 Log.e(TAG_DELEGATE,"d4.name = ${d4.name}") 33 34 d4.value = 1024 35 36 d4.count = 2046 37 38 d4.count = 328 39 40 Log.e(TAG_DELEGATE,"d4.count = ${d4.count}") 41 42 // Log.e(TAG_DELEGATE,"d4.str = ${d4.str}") //error d4.str未初始化。 43 300 44 }
结果
2019-09-13 15:13:25.209 8175-8175/com.example.kotlin E/delegate: ====================================== delegate_test_ 4
2019-09-13 15:13:25.212 8175-8175/com.example.kotlin E/delegate: value onChanged : old = 0,new = 99
2019-09-13 15:13:25.212 8175-8175/com.example.kotlin E/delegate: lazy called
2019-09-13 15:13:25.212 8175-8175/com.example.kotlin E/delegate: d4.name = lazy
2019-09-13 15:13:25.213 8175-8175/com.example.kotlin E/delegate: value onChanged : old = 99,new = 1024
2019-09-13 15:13:25.213 8175-8175/com.example.kotlin E/delegate: count onChanged : old = 8,new = 2046
2019-09-13 15:13:25.213 8175-8175/com.example.kotlin E/delegate: count onChanged : old = 8,new = 328
2019-09-13 15:13:25.213 8175-8175/com.example.kotlin E/delegate: d4.count = 8
map 示例
1 class D9(val map8 : Map<String,Any?>){ 2 val name : String by map8 3 val id : Int by map8 4 5 var T = 200 6 //var age : Int by T //error,Int 并没有提供委托函数。 7 var age : Int = T 8 9 var mmap = mutableMapOf<String,Any?>() 10 var desc : String by mmap 11 12 init{ 13 mmap.put("desc","done") 14 } 15 16 override fun toString(): String { 17 return "name = $name,id = $id,desc = $desc,age = $age" 18 } 19 fun reset(){ 20 mmap.put("desc","null") 21 this.age = 0 22 this::age 23 ::age 24 } 25 } 26 27 fun delegate_test9(){ 28 Log.e(TAG_DELEGATE,"====================================== delegate_test_9 ") 29 var map = mutableMapOf<String,Any?>( 30 "name" to "sia" 31 ,"age" to 12 32 ,"id" to 3 33 ) 34 35 var d9 = D9(map) 36 37 Log.e(TAG_DELEGATE,"d9 = $d9") 38 39 //d9本身的name和id不可修改,但是它的值来自外部map,当map改变时,它们也改了。 40 map.put("name","nick") 41 map.put("id",8) 42 Log.e(TAG_DELEGATE,"d9 = $d9") 43 44 d9.reset() 45 Log.e(TAG_DELEGATE,"d9 = $d9") 46 47 }
结果
2019-09-13 15:13:25.215 8175-8175/com.example.kotlin E/delegate: ====================================== delegate_test_9
2019-09-13 15:13:25.216 8175-8175/com.example.kotlin E/delegate: d9 = name = sia,id = 3,desc = done,age = 200
2019-09-13 15:13:25.216 8175-8175/com.example.kotlin E/delegate: d9 = name = nick,id = 8,desc = done,age = 200
2019-09-13 15:13:25.217 8175-8175/com.example.kotlin E/delegate: d9 = name = nick,id = 8,desc = null,age = 0
5.变量委托的注意事项
5.1 指定初始值时不能使用委托
1 fun delegate_test5(){ 2 Log.e(TAG_DELEGATE,"====================================== delegate_test_5 ") 3 4 val noinit1 : Int = 10 by Delegates.notNull() //error,指定初始值时不能使用委托 5 var noinit2 : Int by Delegates.notNull() //ok 6 noinit2 = 20 7 8 val size = 64 by lazy { Log.e(TAG_DELEGATE,"init"); 32 } //error,size已经初始化。 9 class d8{ 10 var value = 64 by Delegates.notNull<Int>() //error,value已经初始化。 11 } 12 }
结果:第 4、8、10 行编译不过
5.2 类型可以省略
1 fun delegate_test6(){ 2 Log.e(TAG_DELEGATE,"====================================== delegate_test_6 ") 3 4 val notype1 by lazy { 3 } 5 6 val notype2 by lazy { Log.e(TAG_DELEGATE,"init"); "notype2" } 7 8 Log.e(TAG_DELEGATE,"notype1 = $notype1 , notype2 = $notype2") 9 }
结果
2019-09-13 15:41:07.935 8824-8824/com.example.kotlin E/delegate: ====================================== delegate_test_6
2019-09-13 15:41:07.936 8824-8824/com.example.kotlin E/delegate: init
2019-09-13 15:41:07.936 8824-8824/com.example.kotlin E/delegate: notype1 = 3 , notype2 = notype2
5.3 不能同时指定多个委托
1 fun delegate_test7(){ 2 Log.e(TAG_DELEGATE,"====================================== delegate_test_7 ") 3 4 val notype1 by lazy { 3 } ,Delegates.notNull() //error 5 val SIZE by lazy { Log.e(TAG_DELEGATE,"init"); 32 } 6 Log.e(TAG_DELEGATE,"SIZE = $SIZE,不能同时指定多个委托") 7 }
结果: 第4行编译不过