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. fun delegate_test1(){
  12.  
  13. Log.e(TAG_DELEGATE,"====================================== delegate_test_ 1 ")
  14.  
  15. var impl = base1Impl()
  16. var delegate1 = delegate1(impl)
  17.  
  18. delegate1.f2()
  19.  
  20. var d2 = delegate1(object : __base1__{
  21. override fun f2() {
  22. Log.e(TAG_DELEGATE,"delegate1.companion.impl.f2()")
  23. }
  24. })
  25.  
  26. d2.f2()
  27. }

  结果

  1. 2019-09-13 09:46:04.165 25360-25360/com.example.kotlin E/delegate: ====================================== delegate_test_ 1
  2. 2019-09-13 09:46:04.166 25360-25360/com.example.kotlin E/delegate: base1Impl.f2()
  3. 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 声明委托。如下:
    1. 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. }

  结果

  1. 2019-09-13 10:55:35.772 27606-27606/com.example.kotlin E/delegate: ====================================== delegate_test_ 3
  2. 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 = ){
  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 = ){
  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 =
  31.  
  32. Log.e(TAG_DELEGATE,"d4.name = ${d4.name}")
  33.  
  34. d4.value =
  35.  
  36. d4.count =
  37.  
  38. d4.count =
  39.  
  40. Log.e(TAG_DELEGATE,"d4.count = ${d4.count}")
  41.  
  42. // Log.e(TAG_DELEGATE,"d4.str = ${d4.str}") //error d4.str未初始化。
  43.  
  44. }

  结果

  1. 2019-09-13 15:13:25.209 8175-8175/com.example.kotlin E/delegate: ====================================== delegate_test_ 4
  2. 2019-09-13 15:13:25.212 8175-8175/com.example.kotlin E/delegate: value onChanged : old = 0,new = 99
  3. 2019-09-13 15:13:25.212 8175-8175/com.example.kotlin E/delegate: lazy called
  4. 2019-09-13 15:13:25.212 8175-8175/com.example.kotlin E/delegate: d4.name = lazy
  5. 2019-09-13 15:13:25.213 8175-8175/com.example.kotlin E/delegate: value onChanged : old = 99,new = 1024
  6. 2019-09-13 15:13:25.213 8175-8175/com.example.kotlin E/delegate: count onChanged : old = 8,new = 2046
  7. 2019-09-13 15:13:25.213 8175-8175/com.example.kotlin E/delegate: count onChanged : old = 8,new = 328
  8. 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 =
  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 =
  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
  32. ,"id" to
  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",)
  42. Log.e(TAG_DELEGATE,"d9 = $d9")
  43.  
  44. d9.reset()
  45. Log.e(TAG_DELEGATE,"d9 = $d9")
  46.  
  47. }

  结果

  1. 2019-09-13 15:13:25.215 8175-8175/com.example.kotlin E/delegate: ====================================== delegate_test_9
  2. 2019-09-13 15:13:25.216 8175-8175/com.example.kotlin E/delegate: d9 = name = sia,id = 3,desc = done,age = 200
  3. 2019-09-13 15:13:25.216 8175-8175/com.example.kotlin E/delegate: d9 = name = nick,id = 8,desc = done,age = 200
  4. 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 =
  7.  
  8. val size = by lazy { Log.e(TAG_DELEGATE,"init"); } //error,size已经初始化。
  9. class d8{
  10. var value = 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 { }
  5.  
  6. val notype2 by lazy { Log.e(TAG_DELEGATE,"init"); "notype2" }
  7.  
  8. Log.e(TAG_DELEGATE,"notype1 = $notype1 , notype2 = $notype2")
  9. }

  结果

  1. 2019-09-13 15:41:07.935 8824-8824/com.example.kotlin E/delegate: ====================================== delegate_test_6
  2. 2019-09-13 15:41:07.936 8824-8824/com.example.kotlin E/delegate: init
  3. 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"); }
  6. Log.e(TAG_DELEGATE,"SIZE = $SIZE,不能同时指定多个委托")
  7. }

  结果: 第4行编译不过

Kotlin 委托(1)类委托、变量委托注意事项的更多相关文章

  1. Kotlin 委托(2)变量委托是什么、自定义变量委托

    1.委托是什么? 1.1 官网示例 在每个变量委托的实现的背后,Kotlin 编译器都会生成辅助对象并委托给它. 假设委托如下, class C { var prop: Type by MyDeleg ...

  2. Kotlin属性委托系统总结与提供委托详解

    属性委托总结回顾: 在前三次已经将Kotlin委托相关的知识点进行了完整的学习了,具体博文如下: https://www.cnblogs.com/webor2006/p/11369019.html h ...

  3. .NET Core 跨平台物联网开发:SDK 属性、方法、委托、类(四)

    系列教程目录 (一) 连接阿里云IOT (二) 设置委托事件 (三) 上报属性 (四)  SDK文档 属性.方法.委托.类 http://pan.whuanle.cn/index.php?dir=up ...

  4. 自定义委托类型 - .Net自带委托类型

    委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递. 与其他的类不同,委托类具有一个签名,并且它只能对与其签名匹配的方法进行引用. 一.自定义委托类型 1.语法结构:访问修 ...

  5. 链方法[C# 基础知识系列]专题三:如何用委托包装多个方法——委托链

    最近研究链方法,稍微总结一下,以后继续补充: 弁言: 上一专题分析了下编译器是如何来翻译委托的,从中间语言的角度去看委托,希望可以帮助大家进一步的理解委托,然而之前的分析都是委托只是封装一个方法,那委 ...

  6. [C# 基础知识系列]专题三:如何用委托包装多个方法——委托链 (转载)

    引言: 上一专题介绍了下编译器是如何来翻译委托的,从中间语言的角度去看委托,希望可以帮助大家进一步的理解委托,然而之前的介绍都是委托只是封装一个方法,那委托能不能封装多个方法呢?因为生活中经常会听到, ...

  7. 第十节:委托和事件(2)(泛型委托、Func和Action、事件及与委托的比较)

    一. 泛型委托 所谓的泛型委托,即自定义委托的参数可以用泛型约束,同时内置委托Func和Action本身就是泛型委托. 将上一个章节中的Calculator类中的方法用自定义泛型委托重新实现一下. p ...

  8. C# 委托链、多路广播委托

    委托链.多路广播委托:也就是把多个委托链接在一起,我们把链接了多个方法的委托称为委托链或多路广播委托 例: class HelloWorld { //定义委托类型 delegate void Dele ...

  9. Kotlin入门(12)类的概貌与构造

    上一篇文章提到泛型函数appendString是在类外面定义,这不免使人疑惑,类里面又该怎样定义成员函数呢?为解答这个疑问,接下来的几篇文章将好好描述一下Kotlin如何操作类及其对象,本篇文章先对类 ...

随机推荐

  1. ssm项目中使用拦截器加上不生效解决方案

    在很多时候,需要拦截器来帮助我们完成一些特定的工作,比如获取请求的参数,本身在request这种获取数据就是一次磁盘的io, 如果在filter中获取了参数,那么在controller中就不能获取相关 ...

  2. jQuery鼠标拖曳改变div大小(模拟textarea右下角拖曳)

    jQuery.fn.extend({ drag: function() { $(document).off("mouseup.drag").on("mouseup.dra ...

  3. sqllocaldb

    创建实例  sqllocaldb create v12.0 启动实例 sqllocaldb start v12.0

  4. wordpress 插件语法分析器

    在通过查看 apply_filters( 'ap_addon_form_args', array $form_args ) 的html body class中发现wp-parser 字样,就googl ...

  5. openSUSE中启用apache mod_rewrite

    1. 编辑 "/etc/sysconfig/apache2"文件 查找 APACHE_MODULES,你应该会找到一行像 APACHE_MODULES="actions ...

  6. ie中onclick问题

    代码:<button > <span onclick="xxx();">确定</span></button> 在chrome和fir ...

  7. 新安装一个eclipse,导入一个web项目,右键点击项目选择Properties,找不到project facets和Server选项。

    解决方式: 1.点击:eclipse导航栏中点击Help->Install New Software 2.点击Add添加 3在弹出框中填写以下信息 name:keep(名字随便取) locati ...

  8. 在github上怎样克隆vue项目及运行

    长时间不做vue项目,今天看vue项目运行时有些指令忘记了,在这里写下相关指令 .克隆已有项目,一般情况项目中的README.md写的是项目运行步骤,一般项目的运行如下 克隆项目 git clone ...

  9. MSSQLSERVER跨服务器连接(远程登录)的示例代码

    MSSQLSERVER跨服务器链接服务器创建方法如下 复制代码 代码如下: --声明变量 Declare @svrname varchar(255), @dbname varchar(255), @s ...

  10. privoxy 安装

    https://www.privoxy.org/sf-download-mirror/Sources/ 1.挑选源码版本,下载,解压 2.增加用户 useradd privoxy 3.make &am ...