1.委托是什么?

1.1 官网示例

  在每个变量委托的实现的背后,Kotlin 编译器都会生成辅助对象并委托给它。 假设委托如下,

 class C {
var prop: Type by MyDelegate()
}

  那么编译器生成的相应代码如下:

 class C {
private val prop$delegate = MyDelegate()
var prop: Type
get() = prop$delegate.getValue(this, this::prop)
set(value: Type) = prop$delegate.setValue(this, this::prop, value)
}

  其中:

  • val prop$delegate 就是被委托的对象
  • getValue与setValue就是对prop的管理函数

1.2 变量委托是一系列类

  变量委托是重载setValue,getValue运算符的类,可直接重载或者实现ReadWriteProperty、ReadOnlyProperty 接口之一。

     operator fun getValue(thisRef: R, property: KProperty<*>): T
operator fun setValue(thisRef: R, property: KProperty<*>, value: T)

  其中

  • thisRef —— 必须与委托都类型相同或者是它的超类型;
  • property —— 必须是类型 KProperty<*> 或其超类型。
  • value 必须与委托者同类型或者是它的子类型
  • 返回值与委托者相同类型(或其子类型)

  下面看下lazy是怎么实现的

 val i11 by lazy {  }

  点开lazy的实现

/**
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]
* and the default thread-safety mode [LazyThreadSafetyMode.SYNCHRONIZED].
*
* If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access.
*
* Note that the returned instance uses itself to synchronize on. Do not synchronize from external code on
* the returned instance as it may cause accidental deadlock. Also this behavior can be changed in the future.
*/
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)

  lazy是个函数 ,返回Lazy<T> ,再看下Lazy

 /**
* Represents a value with lazy initialization.
*
* To create an instance of [Lazy] use the [lazy] function.
*/
public interface Lazy<out T> {
/**
* Gets the lazily initialized value of the current Lazy instance.
* Once the value was initialized it must not change during the rest of lifetime of this Lazy instance.
*/
public val value: T /**
* Returns `true` if a value for this Lazy instance has been already initialized, and `false` otherwise.
* Once this function has returned `true` it stays `true` for the rest of lifetime of this Lazy instance.
*/
public fun isInitialized(): Boolean
}

  并没有operator getValue,往下看

 /**
* An extension to delegate a read-only property of type [T] to an instance of [Lazy].
*
* This extension allows to use instances of Lazy for property delegation:
* `val property: String by lazy { initializer }`
*/
@kotlin.internal.InlineOnly
public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value

  原来它是扩展重载的getValue运算符。

  再看下Delegates.observable,它返回的 ObservableProperty 实现了 ReadWriteProperty 接口。

    /**
* Returns a property delegate for a read/write property that calls a specified callback function when changed.
* @param initialValue the initial value of the property.
* @param onChange the callback which is called after the change of the property is made. The value of the property
* has already been changed when this callback is invoked.
*
* @sample samples.properties.Delegates.observableDelegate
*/
public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
ReadWriteProperty<Any?, T> =
object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
}
 public abstract class ObservableProperty<T>(initialValue: T) : ReadWriteProperty<Any?, T> {

     //...
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
} public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val oldValue = this.value
if (!beforeChange(property, oldValue, value)) {
return
}
this.value = value
afterChange(property, oldValue, value)
}
}

2.by后面的是什么?

  by后面的是委托类的一个对象

  示例代码

 class lazy11(var default : Int = -,var lmda : () -> Int) {
operator fun provideDelegate( thisRef : Any,prop : KProperty<*>) : Delegate13 {
return Delegate13(lmda)
}
} val i11 by lazy { } class D11{
val MAX by lazy { } var lazy = lazy{ }
val value : Int by lazy var lazy11 = lazy11{}
var count : Int by lazy11
} fun delegate_test11(){
Log.e(TAG_DELEGATE,"====================================== delegate_test_11 ") var d11 = D11()
Log.e(TAG_DELEGATE,"d11.value = ${d11.value},d11.count = ${d11.count} ,d11.MAX = ${d11.MAX}")
}

  结果

2019-09-13 16:54:51.742 10374-10374/com.example.kotlin E/delegate: ====================================== delegate_test_11
2019-09-13 16:54:51.744 10374-10374/com.example.kotlin E/delegate: Delegate13.getValue
2019-09-13 16:54:51.744 10374-10374/com.example.kotlin E/delegate: d11.value = 9,d11.count = 8 ,d11.MAX = 1024

  其中:MAX委托的是编译器生成的对象,而value与count则是直接托委的成员对象。

3.自定义变量委托

3.1 直接重载getValue,setValue运算符

 class BYY{
var value : Int = - operator fun setValue(thisRef: Any, property: KProperty<*>, v : Int) {
Log.e(TAG_DELEGATE,"BYY.setValue")
value = v
}
operator fun getValue(thisRef: Any, property: KProperty<*>): Int {
Log.e(TAG_DELEGATE,"BYY.getValue")
return value
}
}
operator fun BYY.setValue(thisRef: Nothing?, property: KProperty<*>, v : Int){ }
operator fun BYY.get(thisRef: Nothing?, property: KProperty<*>) = value class D12{
var size : Int by BYY()
} fun delegate_test12(){
Log.e(TAG_DELEGATE,"====================================== delegate_test_12 ")
var d12 = D12()
d12.size =
Log.e(TAG_DELEGATE,"d12.size = ${d12.size}") }

  结果

2019-09-13 17:02:43.564 10695-10695/com.example.kotlin E/delegate: ====================================== delegate_test_12
2019-09-13 17:02:43.564 10695-10695/com.example.kotlin E/delegate: BYY.setValue
2019-09-13 17:02:43.564 10695-10695/com.example.kotlin E/delegate: BYY.getValue
2019-09-13 17:02:43.564 10695-10695/com.example.kotlin E/delegate: d12.size = 128

3.2 实现 委托接口

  ReadOnlyProperty 与 ReadWriteProperty 这两个接口声明了getValue,setValue两个运算符,

 class MyDelegate() : ReadOnlyProperty<DC12,Int>,ReadWriteProperty<DC12,Int>{
var value : Int =
override fun setValue(thisRef: DC12, property: KProperty<*>, v : Int) {
Log.e(TAG_DELEGATE,"MyDelegate.setValue ")
value = v
} override fun getValue(thisRef: DC12, property: KProperty<*>) : Int {
Log.e(TAG_DELEGATE,"MyDelegate.setValue ")
return value
}
constructor(lmda : ()-> Int) : this (){
value = lmda()
}
}
fun getNum() : Int{
Log.e(TAG_DELEGATE,"getNum ")
return
} class DC12{
var value : Int by MyDelegate()
var value2 : Int by MyDelegate(::getNum)
} fun delegate_test12(){
Log.e(TAG_DELEGATE,"====================================== delegate_test_12 ") var dc12 = DC12()
dc12.value =
Log.e(TAG_DELEGATE,"dc12.value = ${dc12.value},dc12.value2 = ${dc12.value2}")
}

  结果

2019-09-13 17:04:07.213 10931-10931/com.example.kotlin E/delegate: ====================================== delegate_test_12
2019-09-13 17:04:07.214 10931-10931/com.example.kotlin E/delegate: getNum
2019-09-13 17:04:07.214 10931-10931/com.example.kotlin E/delegate: MyDelegate.setValue
2019-09-13 17:04:07.214 10931-10931/com.example.kotlin E/delegate: MyDelegate.setValue
2019-09-13 17:04:07.214 10931-10931/com.example.kotlin E/delegate: MyDelegate.setValue
2019-09-13 17:04:07.214 10931-10931/com.example.kotlin E/delegate: dc12.value = 64,dc12.value2 = 33

3.3 委托提供运算符 provideDelegate

  如果 by 右侧所使用的对象将 provideDelegate 定义为成员或扩展函数,那么会调用该函数来创建属性委托实例。

 class Delegate13 (lmda: () -> Int) : ReadOnlyProperty<Any,Int>,ReadWriteProperty<Any,Int>{
var COUNT : Int
init{
COUNT = lmda()
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) {
Log.e(TAG_DELEGATE,"Delegate13.setValue")
COUNT = value
}
override fun getValue(thisRef: Any, property: KProperty<*>): Int {
Log.e(TAG_DELEGATE,"Delegate13.getValue")
return COUNT
}
}
class mutableLazy(var default : Int = -,var lmda : () -> Int) {
operator fun provideDelegate( thisRef : Any,prop : KProperty<*>) : Delegate13 {
return Delegate13(lmda)
}
} class D13{
var value : Int by mutableLazy{
Log.e(TAG_DELEGATE,"mutableLazy.lmda") }
} fun delegate_test13(){
Log.e(TAG_DELEGATE,"====================================== delegate_test_13 ") var d13 = D13()
Log.e(TAG_DELEGATE,"d13.value = ${d13.value}") d13.value =
Log.e(TAG_DELEGATE,"d13.value = ${d13.value}")
}

  结果

2019-09-13 20:52:31.350 25146-25146/com.example.kotlin E/delegate: ====================================== delegate_test_13
2019-09-13 20:52:31.350 25146-25146/com.example.kotlin E/delegate: mutableLazy.lmda
2019-09-13 20:52:31.350 25146-25146/com.example.kotlin E/delegate: Delegate13.getValue
2019-09-13 20:52:31.350 25146-25146/com.example.kotlin E/delegate: d13.value = 99
2019-09-13 20:52:31.350 25146-25146/com.example.kotlin E/delegate: Delegate13.setValue
2019-09-13 20:52:31.350 25146-25146/com.example.kotlin E/delegate: Delegate13.getValue
2019-09-13 20:52:31.351 25146-25146/com.example.kotlin E/delegate: d13.value = 299

Kotlin 委托(2)变量委托是什么、自定义变量委托的更多相关文章

  1. v9站点自定义变量

    打开 \phpcms\modules\admin\templates\site_edit.tpl.php 文件,找到最后一个 </fieldset> ,在他后面添加一下代码:<!-- ...

  2. 匿名方法、Lambda表达和自定义泛型委托以及Func、Action系统泛型委托

    1.匿名方法的概念:一个方法没有具体的名称,而只有关键字delegate.方法参数.方法体.这种方法是匿名方法. 匿名方法的好处:将具体方法和委托直接关联在一起,如果我们基于委托只需要一个方法的时候, ...

  3. 【详细】【转】C#中理解委托和事件 事件的本质其实就是委托 RabbitMQ英汉互翼(一),RabbitMQ, RabbitMQ教程, RabbitMQ入门

    [详细][转]C#中理解委托和事件   文章是很基础,但很实用,看了这篇文章,让我一下回到了2016年刚刚学委托的时候,故转之! 1.委托 委托类似于C++中的函数指针(一个指向内存位置的指针).委托 ...

  4. 委托、Lambda表达式、事件系列04,委托链是怎样形成的, 多播委托, 调用委托链方法,委托链异常处理

    委托是多播委托,我们可以通过"+="把多个方法赋给委托变量,这样就形成了一个委托链.本篇的话题包括:委托链是怎样形成的,如何调用委托链方法,以及委托链异常处理. □ 调用返回类型为 ...

  5. 委托、Lambda表达式、事件系列01,委托是什么,委托的基本用法,委托的Method和Target属性

    委托是一个类. namespace ConsoleApplication1 { internal delegate void MyDelegate(int val); class Program { ...

  6. 用五分钟重温委托,匿名方法,Lambda,泛型委托,表达式树

    这些对老一代的程序员都是老生常谈的东西,没什么新意,对新生代的程序员却充满着魅力.曾经新生代,好多都经过漫长的学习,理解,实践才能掌握委托,表达式树这些应用.今天我尝试用简单的方法叙述一下,让大家在五 ...

  7. 转帖:用五分钟重温委托,匿名方法,Lambda,泛型委托,表达式树

    用五分钟重温委托,匿名方法,Lambda,泛型委托,表达式树 这些对老一代的程序员都是老生常谈的东西,没什么新意,对新生代的程序员却充满着魅力.曾经新生代,好多都经过漫长的学习,理解,实践才能掌握委托 ...

  8. C#中使用委托、接口、匿名方法、泛型委托实现加减乘除算法

    使用C#实现加减乘除算法经常被用作新手练习.本篇来分别体验通过委托.接口.匿名方法.泛型委托来实现. 使用委托实现 加减乘除拥有相同的参数个数.类型和返回类型,首先想到了使用委托实现. //创建一个委 ...

  9. 【持续集成】[Jenkins]Job中如何传递自定义变量

    [Jenkins]Job中如何传递自定义变量 来自dweiwei   2015-06-27 18:37:19|  分类: 自动化测试 |举报 |字号大中小 订阅 用微信  “扫一扫” 将文章分享到朋友 ...

随机推荐

  1. 使用CEfSharp之旅(3)下载文件 弹出保存框 IDownloadHandler

    原文:使用CEfSharp之旅(3)下载文件 弹出保存框 IDownloadHandler 版权声明:本文为博主原创文章,未经博主允许不得转载.可点击关注博主 ,不明白的进群191065815 我的群 ...

  2. Java工具类NumberUtils使用

    int数据类型和long数据类型 int占32位,long占64位,long表示的数据更大:public static int toInt(String str) NumberUtils.toInt( ...

  3. 2019-9-2-贡献自己的服务器搭建tor中转

    title author date CreateTime categories 贡献自己的服务器搭建tor中转 lindexi 2019-09-02 12:57:38 +0800 2018-2-13 ...

  4. No packages marked for update

    问题:用yum安装docker,更新yum存储时,报以下错误,导致yum坏了 [root@localhost yum.repos.d]# vi docker.repo [root@localhost ...

  5. 用shell编写小九九乘法表程序

    1.使用for循环 运行结果: 2.方法二:for循环 运行结果: 备注: 1. echo -n 的意思是不自动换行,因为在linux shell中 echo到最后一个字符时会自动换行的,所以echo ...

  6. IDE 插件新版本发布,开发效率 “biu” 起来了

    近日,Cloud Toolkit正式推出了面向 IntelliJ 和 Eclipse 两个平台的新款插件,本文挑选了其中三个重大特性进行解读,点击文末官网跳转链接,可查看详细的版本说明. 本地应用一键 ...

  7. 【玲珑杯 round#18 A】计算几何你瞎暴力

    [Link]:http://www.ifrog.cc/acm/problem/1143?contest=1020&no=0 [Description] [Solution] 因为每个点的(xi ...

  8. mysql索引优化及explain关键字段解释

    一.explain关键字解释 1.id MySQL QueryOptimizer 选定的执行计划中查询的序列号,表示查询中执行select 子句或操作表的顺序.id 值越大优先级越高,越先被执行.id ...

  9. 图数据库neo4j和关系数据库的区别

    相信您和我一样,在使用关系型数据库时常常会遇到一系列非常复杂的设计问题.例如一部电影中的各个演员常常有主角配角之分,还要有导演,特效等人员的参与.通常情况下这些人员常常都被抽象为Person类型,对应 ...

  10. 记录:vue结合springboot进行分页查询和按条件进行查询

    界面: 主要代码: 搜索框: <el-form ref="searchForm" :inline="true" :model="searchMa ...