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 示例
interface __base1__ { fun f2() }
class base1Impl : __base1__ {
override fun f2() {
Log.e(TAG_DELEGATE,"base1Impl.f2()")
}
}
class delegate1(var impl : __base1__) : __base1__ by impl
fun delegate_test1(){
Log.e(TAG_DELEGATE,"====================================== delegate_test_ 1 ")
var impl = base1Impl()
var delegate1 = delegate1(impl)
delegate1.f2()
var d2 = delegate1(object : __base1__{
override fun f2() {
Log.e(TAG_DELEGATE,"delegate1.companion.impl.f2()")
}
})
d2.f2()
}
结果
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 接口能被委托,类不可以
open class deleagte_base2
open class delegate_sub1 : deleagte_base2()
class delegate1(base1 : deleagte_base2) : deleagte_base2 by base1 //error 只有接口能被委托,类不可以 abstract class AB1{
abstract fun f1()
}
class D2 (var ab : AB1) : AB1 by ab //error,抽象类也不可以委托。
结果: 第3、8 行编译不过。
3.3 不要重写委托接口的方法
不要重写委托接口的方法,否则调用的是重写版本的,不是委托对象的。
interface __I3__ { fun f3() }
class I3Impl : __I3__{
override fun f3() {
Log.e(TAG_DELEGATE,"I3Impl.f3()")
}
}
class delegate3(i3 : __I3__) : __I3__ by i3 {
override fun f3() { //不要重写委托类的方法,否则调用的是重写的,不是委托的。
Log.e(TAG_DELEGATE,"delegate3.f3()")
}
}
fun delegate_test3(){
Log.e(TAG_DELEGATE,"====================================== delegate_test_ 3 ")
var im3 = I3Impl()
var delegate3 = delegate3(im3)
delegate3.f3()
}
结果
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 自带变量委托示例
//成员变量使用委托属性
class delegate4{ val name : String by lazy(mode = LazyThreadSafetyMode.NONE){
//mode = LazyThreadSafetyMode.PUBLICATION 表示关闭同步锁,默认开启同步锁的
Log.e(TAG_DELEGATE,"lazy called ")
"lazy"
} var value : Int by Delegates.observable(initialValue = ){
prop,old,new ->
Log.e(TAG_DELEGATE,"${prop.name} onChanged : old = $old,new = $new")
} var count : Int by Delegates.vetoable(initialValue = ){
prop,old,new ->
Log.e(TAG_DELEGATE,"${prop.name} onChanged : old = $old,new = $new ")
false //return false 表示不接受修改,本次修改被否决
} var str : String by Delegates.notNull() //在未初始化前使用,IllegalStateException。 } fun delegate_test4(){
Log.e(TAG_DELEGATE,"====================================== delegate_test_ 4 ") var d4 = delegate4() d4.value = Log.e(TAG_DELEGATE,"d4.name = ${d4.name}") d4.value = d4.count = d4.count = Log.e(TAG_DELEGATE,"d4.count = ${d4.count}") // Log.e(TAG_DELEGATE,"d4.str = ${d4.str}") //error d4.str未初始化。 }
结果
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 示例
class D9(val map8 : Map<String,Any?>){
val name : String by map8
val id : Int by map8
var T =
//var age : Int by T //error,Int 并没有提供委托函数。
var age : Int = T
var mmap = mutableMapOf<String,Any?>()
var desc : String by mmap
init{
mmap.put("desc","done")
}
override fun toString(): String {
return "name = $name,id = $id,desc = $desc,age = $age"
}
fun reset(){
mmap.put("desc","null")
this.age =
this::age
::age
}
}
fun delegate_test9(){
Log.e(TAG_DELEGATE,"====================================== delegate_test_9 ")
var map = mutableMapOf<String,Any?>(
"name" to "sia"
,"age" to
,"id" to
)
var d9 = D9(map)
Log.e(TAG_DELEGATE,"d9 = $d9")
//d9本身的name和id不可修改,但是它的值来自外部map,当map改变时,它们也改了。
map.put("name","nick")
map.put("id",)
Log.e(TAG_DELEGATE,"d9 = $d9")
d9.reset()
Log.e(TAG_DELEGATE,"d9 = $d9")
}
结果
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 指定初始值时不能使用委托
fun delegate_test5(){
Log.e(TAG_DELEGATE,"====================================== delegate_test_5 ")
val noinit1 : Int = 10 by Delegates.notNull() //error,指定初始值时不能使用委托
var noinit2 : Int by Delegates.notNull() //ok
noinit2 =
val size = by lazy { Log.e(TAG_DELEGATE,"init"); } //error,size已经初始化。
class d8{
var value = by Delegates.notNull<Int>() //error,value已经初始化。
}
}
结果:第 4、8、10 行编译不过
5.2 类型可以省略
fun delegate_test6(){
Log.e(TAG_DELEGATE,"====================================== delegate_test_6 ")
val notype1 by lazy { }
val notype2 by lazy { Log.e(TAG_DELEGATE,"init"); "notype2" }
Log.e(TAG_DELEGATE,"notype1 = $notype1 , notype2 = $notype2")
}
结果
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 不能同时指定多个委托
fun delegate_test7(){
Log.e(TAG_DELEGATE,"====================================== delegate_test_7 ")
val notype1 by lazy { 3 } ,Delegates.notNull() //error
val SIZE by lazy { Log.e(TAG_DELEGATE,"init"); }
Log.e(TAG_DELEGATE,"SIZE = $SIZE,不能同时指定多个委托")
}
结果: 第4行编译不过
Kotlin 委托(1)类委托、变量委托注意事项的更多相关文章
- Kotlin 委托(2)变量委托是什么、自定义变量委托
1.委托是什么? 1.1 官网示例 在每个变量委托的实现的背后,Kotlin 编译器都会生成辅助对象并委托给它. 假设委托如下, class C { var prop: Type by MyDeleg ...
- Kotlin属性委托系统总结与提供委托详解
属性委托总结回顾: 在前三次已经将Kotlin委托相关的知识点进行了完整的学习了,具体博文如下: https://www.cnblogs.com/webor2006/p/11369019.html h ...
- .NET Core 跨平台物联网开发:SDK 属性、方法、委托、类(四)
系列教程目录 (一) 连接阿里云IOT (二) 设置委托事件 (三) 上报属性 (四) SDK文档 属性.方法.委托.类 http://pan.whuanle.cn/index.php?dir=up ...
- 自定义委托类型 - .Net自带委托类型
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递. 与其他的类不同,委托类具有一个签名,并且它只能对与其签名匹配的方法进行引用. 一.自定义委托类型 1.语法结构:访问修 ...
- 链方法[C# 基础知识系列]专题三:如何用委托包装多个方法——委托链
最近研究链方法,稍微总结一下,以后继续补充: 弁言: 上一专题分析了下编译器是如何来翻译委托的,从中间语言的角度去看委托,希望可以帮助大家进一步的理解委托,然而之前的分析都是委托只是封装一个方法,那委 ...
- [C# 基础知识系列]专题三:如何用委托包装多个方法——委托链 (转载)
引言: 上一专题介绍了下编译器是如何来翻译委托的,从中间语言的角度去看委托,希望可以帮助大家进一步的理解委托,然而之前的介绍都是委托只是封装一个方法,那委托能不能封装多个方法呢?因为生活中经常会听到, ...
- 第十节:委托和事件(2)(泛型委托、Func和Action、事件及与委托的比较)
一. 泛型委托 所谓的泛型委托,即自定义委托的参数可以用泛型约束,同时内置委托Func和Action本身就是泛型委托. 将上一个章节中的Calculator类中的方法用自定义泛型委托重新实现一下. p ...
- C# 委托链、多路广播委托
委托链.多路广播委托:也就是把多个委托链接在一起,我们把链接了多个方法的委托称为委托链或多路广播委托 例: class HelloWorld { //定义委托类型 delegate void Dele ...
- Kotlin入门(12)类的概貌与构造
上一篇文章提到泛型函数appendString是在类外面定义,这不免使人疑惑,类里面又该怎样定义成员函数呢?为解答这个疑问,接下来的几篇文章将好好描述一下Kotlin如何操作类及其对象,本篇文章先对类 ...
随机推荐
- linux常用软连接使用ln -s
[软连接]另外一种连接称之为符号连接(Symbolic Link),也叫软连接.软链接文件有类似于Windows的快捷方式.它实际上是一个特殊的文件.在符号连接中,文件实际上是一个文本文件,其中包含的 ...
- [记录]学习树莓派3B接DHT11和LCD1602和修改树莓派时区
前提 树莓派系统安装好 apache web 服务器,如未安装,可在树莓派内执行sudo apt-get install apache2 进行安装apache 也可以通过命令获取GPIO信息: gpi ...
- NSLayoutConstraint 开源框架
https://github.com/cloudkite/Masonry Masonry is a light-weight layout framework which wraps AutoLayo ...
- 洛谷P5104 红包发红包
题目链接: P5104 题目分析: 题目和\(n\)是没什么关系的,因为是\(n\)个人抢,其实不一定抢完 其实很显然--就是求一个连续型随机变量的期望 首先设一个随机变量\(X\),表示第一个人拿到 ...
- memcache课程---3、php使用memcache缓存实例
memcache课程---3.php使用memcache缓存实例 一.总结 一句话总结: 前置:windows下安装好memcache.exe,安装好memcache的php扩展,开启memcache ...
- x64:x64
ylbtech-x64:x64 “x86-64”,有时会简称为“x64”,是64位微处理器架构及其相应指令集的一种,也是Intel x86架构的延伸产品.“x86-64”1999由AMD设计,AMD首 ...
- Android基础控件ProgressBar进度条的使用
1.简介 ProgressBar继承与View类,直接子类有AbsSeekBar和ContentLoadingProgressBar, 其中AbsSeekBar的子类有SeekBar和RatingBa ...
- Python(三)基础篇之「模块&面向对象编程」
[笔记]Python(三)基础篇之「模块&面向对象编程」 2016-12-07 ZOE 编程之魅 Python Notes: ★ 如果你是第一次阅读,推荐先浏览:[重要公告]文章更新. ...
- struts2的default.properties详解
Struts 2框架有两个核心配置文件:struts.xml和struts.properties 其中struts.xml文件主要负责管理应用中的Action映射,以及该Action包含的Result ...
- Data too long for column
一篇文章的正文,需要很多字数,默认就是255,不够 @Lob @Basic @Type(type = "text") @Column(name = "detail&quo ...