Kotlin委托

委托
委托 == 代理
方法内的成员永远拿不到thisRef:官方委托和自定义委托-》方法里面没办法使用反射
委托只能类委托和属性委托

Kotlin委托

本文链接:https://blog.csdn.net/feather_wch/article/details/132095759

类委托

1、类委托

  1. 委托的是接口的方法
// 只能用于接口
interface DB{fun save()
}
// 类CreateDBAction实现了接口DB,参数db是DB类型,类的实现委托给参数db。
// 目的:啥也不想干
class CreateDBAction(db: DB):DB by db

2、类委托的原理是什么?生成了什么代码?

  1. 成员变量:$$delegate_0 = 参数db
  2. 实现方法:委托给$$delegate_0调用save()
public final class CreateDBAction implements DB {// $FF: synthetic fieldprivate final DB $$delegate_0;public CreateDBAction(@NotNull DB db) {Intrinsics.checkNotNullParameter(db, "db");super();this.$$delegate_0 = db;}public void save() {this.$$delegate_0.save();}
}

3、类委托有什么用?

  1. 减少委托的代码
  2. Compose是重委托
CreateDBAction(SqlDB()).save()
CreateDBAction(OracleDB()).save()

属性委托

1、属性委托,委托的是 属性的 set和get

class MyKt{var value = 1314var number by ::value // 两个属性公用get和set
}
// number -> getNumber() -> getValue()
// number = 10 -> setNumber(10) -> setValue(10)

2、委托属性有什么用?

  1. 字段升级,老字段适配老用户,新字段用于新用户。共用一个get、set
class Database{var data = 941226 // 1.0var newData by ::data // 2.0
}

3、懒加载委托也就是属性委托

  1. 第一次获取时,才会获取,下面例子第一次获取耗时2秒,其他都立马获得
fun requestDownload(): String{Thread.sleep(2000L)return "sucess"
}// 懒加载,
// 属性委托,委托给
val responseData : String by lazy {requestDownload()
}
// val responseData : String = SynchronizedLazyImpl(requestDownload())
// 借助了SynchronizedLazyImpl的get方法fun main(){println("startloading...")println(responseData)println(responseData)println(responseData)
}

自定义属性委托

1、完全自己实现属性委托

// 自定义委托,定义好get和set之后,属性可以用该类实现属性委托
class Custom{operator fun getValue(owner: Owner, property: KProperty<*>) : String{return "AAA"}operator fun setValue(owner: Owner, property: KProperty<*>, value :String){}
}
class Owner{val responseData : String by Custom()
}

2、利用模板实现属性委托:ReadWriteProperty

// 自定义委托
class Custom2 : ReadWriteProperty<Owner, String>{var str = "default"override fun getValue(thisRef: Owner, property: KProperty<*>): String {return str}override fun setValue(thisRef: Owner, property: KProperty<*>, value: String) {str = value}
}

提供委托/暴露者委托

1、provideDelegate

  1. 额外的属性初始化逻辑:在属性被委托对象初始化之前进行一些额外的操作,例如数据验证、计算或日志记录等。
  2. 针对不同属性的不同行为:通过在不同的委托对象的provideDelegate方法中实现不同的逻辑,可以根据属性的不同需求,为每个属性提供不同的行为。
  3. 属性访问的可扩展性:可以为属性访问添加自定义的行为,例如缓存、延迟加载、权限控制等。
class Owner{val responseData : String by Custom()
}
// 自定义委托
class Custom(var str: String = "Default") : ReadWriteProperty<Owner, String>{override fun getValue(thisRef: Owner, property: KProperty<*>): String {return str}override fun setValue(thisRef: Owner, property: KProperty<*>, value: String) {str = value}
}
// provideDelegate,暴露者委托,== 选择器
class SmartDelegator{operator fun provideDelegate(thisRef:Owner, property: KProperty<*>):ReadWriteProperty<Owner, String>{return if(property.name.isEmpty()){Custom("empty")}else{Custom("normal")}}
}

实战场景

自己实现by lazy

class LazyInitDelegate<T> {private var initializer: (() -> T)? = nulloperator fun getValue(thisRef: Any?, property: KProperty<*>): T {return initializer?.invoke() ?: throw IllegalStateException("Property not initialized")}operator fun setValue(thisRef: Any?, property: KProperty<*>, value: (() -> T)) {initializer = value}
}class Example {val lazyProperty: String by LazyInitDelegate {// 在第一次访问属性时执行初始化逻辑println("Initializing lazy property")"Lazy Initialized"}
}fun main() {val example = Example()println(example.lazyProperty) // 输出:Initializing lazy property \n Lazy Initialized
}

属性委托的日志记录

import kotlin.reflect.KMutableProperty
import kotlin.reflect.KPropertyclass LoggingDelegate<T> {operator fun getValue(thisRef: Any?, property: KProperty<*>): T {val value = property.getter.call()println("Property ${property.name} is accessed, value: $value")return value as T}operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {println("Property ${property.name} is set with value: $value")(property as KMutableProperty).setter.call(thisRef, value)}
}class Example {var property: String by LoggingDelegate()
}fun main() {val example = Example()example.property = "New value" // 输出:Property property is set with value: New valueprintln(example.property) // 输出:Property property is accessed, value: New value \n New value
}

viewmodel

1、如何做到属性内部可以修改,外部不可以修改?

class Data{var data:String = ""private setprivate void changeData(value:String){data = value}
}
val data = Data()
data.data = "" // xxx 不可以
println(data.data) // 可以

2、如何做到kotlin的list集合,对内可以修改,对外界不可以修改

class MyKt{// 内部可以修改private val _data : MutableList<String> = mutableListOf()// 外部不可以修改val data : List<String> by :: _data
}

3、使用::用官方自定义委托,不使用需要自定义委托

4、用委托实现ViewModel的自动构造

class MyViewModel : ViewModel() {}fun main() {// 委托实现val mainViewModel : MyViewModel by viewModels()
}private fun MainActivity.viewModels() : ReadOnlyProperty<MainActivity?, MyViewModel> =object : ReadOnlyProperty<MainActivity?, MyViewModel>{override fun getValue(thisRef: MainActivity?, property: KProperty<*>): MyViewModel {// thisRef永远为nullreturn ViewModelProvider(this@viewModels).get(MyViewModel::class.java)}}

委托TextView:类似DataBinding

//  
operator fun TextView.provideDelegate(value: Any?, property: KProperty<*>) =object: ReadWriteProperty<Any?, String?>{override fun getValue(thisRef: Any?, property: KProperty<*>): String? {return text as String}override fun setValue(thisRef: Any?, property: KProperty<*>, value: String?) {text = value}}// 创建TextView控件,双向绑定
var textView : TextView = findViewById(R.id.tv)
var message:String ? by textViewtextView.text = "更改了控件的text -> message中的数值也会变"message = "更改了数据 -> 更新UI"

双向绑定,多个控件操作数据

var data1 : String by textView1
var data2 : String by textView2
var data3 : String by textView3data3 = data2
data2 = data1
data1 = "我在吃饭哦"
// 操作数据,View就会变,不用管UI刷新数据

出题目:如何手动实现String的代理(局部变量)?(用扩展函数)

var s1 = "wch"
var s2 : String by ::s1 // 类的成员变量才可以
var s3 : String by s1 // 不用官方的::fun main() {var s1 = "wch"var s2:String by s1 // 报错
}
// Kotlin反射机制
operator fun String.setValue(item: Any?, property: KProperty<*>, value:String){// import kotlin.reflect.jvm.javaField, 已经被移除// property.javaField?.isAccessible = true// property.javaField?.set(item, value)
}
operator fun String.getValue(item: Any?, property: KProperty<*>) = this

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/24932.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Springboot+Easyexcel将数据写入模板文件并导出Excel

SpringbootEasyexcel将数据写入模板文件并导出Excel 一、导入依赖二、根据excel表头创建对应的实体类Pojo三、Controller类接收请求四、Service层获取待写入数据五、效果展示六、总结 一、导入依赖 <!--操作excel工具包--> <dependency><groupId>com.alibab…

剑指 Offer 20. 表示数值的字符串 (正则 逐步分解)

文章目录 题目描述题目分析法一&#xff1a;完整代码: 法二&#xff1a;完整代码: 题目描述 请实现一个函数用来判断字符串是否表示数值&#xff08;包括整数和小数&#xff09;。 数值&#xff08;按顺序&#xff09;可以分成以下几个部分&#xff1a; 若干空格 一个 小数 或者…

[Flask]SSTI1

根据题目提示&#xff0c;这关应该是基于Python flask的模版注入&#xff0c;进入靶场环境后就是一段字符串&#xff0c;而且没有任何提示&#xff0c;有点难受&#xff0c;主要是没有提示注入点 随机尝试一下咯&#xff0c;首先尝试一下guest&#xff0c;GET传参 但是没有反应…

离散Hopfield神经网络的联想记忆与matlab实现

1案例背景 1.1离散Hopfield神经网络概述 Hopfield网络作为一种全连接型的神经网络,曾经为人工神经网络的发展开辟了新的研究途径。它利用与阶层型神经网络不同的结构特征和学习方法,模拟生物神经网络的记忆机理,获得了令人满意的结果。这一网络及学习算法最初是由美国物理学家…

react中hooks的理解与使用

一、作用 我们知道react组件有两种写法一种是类组件&#xff0c;另一种是函数组件。而函数组件是无状态组件&#xff0c;如果我们要想改变组件中的状态就无法实现了。为此&#xff0c;在react16.8版本后官方推出hooks&#xff0c;用于函数组件更改状态。 二、常用API 1、use…

【css】css隐藏元素

display:none&#xff1a;可以隐藏元素。该元素将被隐藏&#xff0c;并且页面将显示为好像该元素不在其中。visibility:hidden&#xff1a; 可以隐藏元素。但是&#xff0c;该元素仍将占用与之前相同的空间。元素将被隐藏&#xff0c;但仍会影响布局。 代码&#xff1a; <!…

go编译文件

1.编译go文件 go build [go文件]2.执行文件编译文件 ./demo [demo为go文件名称]

当服务器域名出现解析错误的问题该怎么办?

​  域名解析是互联网用户接收他们正在寻找的域的地址的过程。更准确地说&#xff0c;域名解析是人们在浏览器中输入时使用的域名与网站IP地址之间的转换过程。您需要站点的 IP 地址才能知道它所在的位置并加载它。但&#xff0c;在这个过程中&#xff0c;可能会出现多种因素…

web服务

静态网页与动态网页的区别 在网站设计中&#xff0c;静态网页是网站建设的基础&#xff0c;纯粹 HTML 格式的网页通常被称为“静态网页”&#xff0c;静态网页是标准的 HTML 文件&#xff0c;它的文件扩展名是 .htm、.html&#xff0c;可以包含文本、图像、声音、FLASH 动画、…

MySQL(1)

MySQL创建数据库和创建数据表 创建数据库 1. 连接 MySQL mysql -u root -p 2. 查看当前的数据库 show databases; 3. 创建数据库 create database 数据库名; 创建数据库 4. 创建数据库时设置字符编码 create database 数据库名 character set utf8; 5. 查看和显示…

Android 音频开发

在Android平台上进行音频开发&#xff0c;您需要掌握以下关键知识点&#xff1a; Android平台基础知识&#xff1a;熟悉Android操作系统的基本架构、组件和应用开发的基本概念。 音频API&#xff1a;了解Android提供的音频相关API&#xff0c;主要包括android.media.AudioReco…

【前瞻】视频技术的发展趋势讨论以及应用场景

视频技术的发展可以追溯到19世纪初期的早期实验。到20世纪初期&#xff0c;电视技术的发明和普及促进了视频技术的进一步发展。 1&#xff09;数字化&#xff1a;数字化技术的发明和发展使得视频技术更加先进。数字电视信号具有更高的清晰度和更大的带宽&#xff0c;可以更快地…

Spring源码解析(七):bean后置处理器AutowiredAnnotationBeanPostProcessor

Spring源码系列文章 Spring源码解析(一)&#xff1a;环境搭建 Spring源码解析(二)&#xff1a;bean容器的创建、默认后置处理器、扫描包路径bean Spring源码解析(三)&#xff1a;bean容器的刷新 Spring源码解析(四)&#xff1a;单例bean的创建流程 Spring源码解析(五)&…

SSE技术和WebSocket技术实现即时通讯

文章目录 一、SSE1.1 什么是SSE1.2 工作原理1.3 特点和适用场景1.4 API用法1.5 代码实现 二、WebSocket2.1 什么是WebSocket2.2 工作原理2.3 特点和适用场景2.4 API用法2.5 代码实现 三、SSE与WebSocket的比较 当涉及到实现实时通信的Web应用程序时&#xff0c;两种常见的技术选…

Agile manifesto principle (敏捷宣言的原则)

Agile Workflow Agile在管理中越来越受推崇&#xff0c;最初是由于传统的软件开发管理方式&#xff08;瀑布模型&#xff09;面对日益复杂的需求&#xff0c;无法Delivery令人满意的结果&#xff0c;经过总结探索&#xff0c;2001年&#xff0c;由行业代表在一次聚会中提出Agil…

桥接模式(C++)

定义 将抽象部分(业务功能)与实现部分(平台实现)分离&#xff0c;使它们都可以独立地变化。 使用场景 由于某些类型的固有的实现逻辑&#xff0c;使得它们具有两个变化的维度&#xff0c;乃至多个纬度的变化。如何应对这种“多维度的变化”?如何利用面向对象技术来使得类型…

Ubuntu服务器版配置wifi

最近把曾经不用的上网本安装了一个Ubuntu-Server版&#xff0c;当成服务器来用&#xff0c;因为家庭网络布线问题&#xff0c;只好用自带的WIFI来连接网络&#xff0c;Server版也没有什么图形化的管理工具&#xff0c;之后手动编辑配置文件了。 Server下面配置起来还是很方便的…

四、FreeRTOS创建任务和源码结构

说明&#xff1a;该内容示例在如下博客的基础上进行。 三、从官方源码精简出第1个FreeRTOS_朱嘉鼎的博客-CSDN博客 1、创建任务 (1)程序 /*任务1的函数*/ void Task1Function( void * param) {while(1){printf("task1\r\n");} }/*任务2的函数*/ void Task2Functi…

Elasticsearch 商业启示

上月的“红帽事件”&#xff0c;说明开源软件的“客服模式”行不通&#xff0c;那么&#xff0c;开源软件如何赚钱呢&#xff1f;既不能卖软件&#xff0c;又不能卖支持服务&#xff0c;该怎么办呢&#xff1f;我现在的看法是&#xff0c;只剩下一种模式是可行的&#xff0c;开…

博客项目测试报告

✏️作者&#xff1a;银河罐头 &#x1f4cb;系列专栏&#xff1a;JavaEE &#x1f332;“种一棵树最好的时间是十年前&#xff0c;其次是现在” 目录 一、项目背景二、项目功能三、测试计划一&#xff09;功能测试二&#xff09;自动化测试三&#xff09;性能测试编写性能测试…