当前位置: 首页 > news >正文

kotlin 委托

一、类委托

interface DB{fun insert()
}
class SqliteDB : DB {override fun insert() {println(" SqliteDB insert")}
}class MySql : DB{override fun insert() {println(" MySql insert")}
}class OracleDB : DB{override fun insert() {println(" OracleDB insert")}
}class CreateDB(db:DB) : DB by dbfun main() {val db = CreateDB(MySql())db.insert()
}

运行main()方法:

CreateDB类需要实现的接口(DB)方法委托给了具体实现类(MySql、OracleDB、SqliteDB)来实现,我认为这和设计模式中的策略模式如出一辙。

通过AndroidStudio的自带工具

Tools -> kotlin -> show kotlin Bytecode ,然后点Decompile,将字节码进行反编译得到java代码

也能佐证我们的想法:

二、委托属性

private var floatValue = 789.12
private var num by ::floatValuefun main() {println("num:$num")num = 567.88println("floatValue:$floatValue")
}

运行结果:

这个示例中将属性num委托给了 属性floatValue,即对num进行get和set操作其实都作用在了floatValue上,因此会有上面的运行结果。

同样我们可以看下反编译后的代码:

让我们稍感惊讶的是,经过转换后甚至都没有定义num这个属性,只是增加了getNum和setNum两个方法来获取和改变floatValue的值。

三、自定义委托

方式1:

class Test3{var text:String by StringDelegate()
}class StringDelegate{operator fun getValue(owner:Any,property:KProperty<*>):String{return "delegate value"}operator fun setValue(owner:Any,property:KProperty<*>,value:String){println("value:$value")}
}fun main() {val t = Test3()println("text:${t.text}")t.text = "haha"
}

要点:

  1. 想要成为可接受委托的类需要实现运算符重载方法,若委托类实现了getValue和setValue(即可读可写),则被委托属性text可用var修饰;若委托类只实现了getValue(即只读),则被委托属性text可用val修饰。
  2. getValue的返回值,和setValue的value参数值类型要与被委托属性类型一致。
  3. getValue和setValue中的owner参数必须是被委托属性text所属的类或其父类。

方式2:

class Test3{var text:String by StringDelegate()var text2:String by StringDelegate2()
}class StringDelegate{operator fun getValue(owner:Any,property:KProperty<*>):String{return "delegate value"}operator fun setValue(owner:Any,property:KProperty<*>,value:String){println("value:$value")}
}class StringDelegate2:ReadWriteProperty<Any,String>{override fun getValue(thisRef: Any, property: KProperty<*>): String {return "delegate value2"}override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {println("value2:$value")}}fun main() {val t = Test3()println("text:${t.text}")t.text = "haha"println("text2:${t.text2}")t.text2 = "haha"
}

要点:

  1. 这种方式的原理就是方式一,只不过是系统Api给我们提供了一种相对方便的使用方式。
  2. 此方式需要出入两个泛型,第一个必须是被委托属性text所属的类或其父类,第二个是被委托属性的类型
  3. 若委托类支持可读可写则继承ReadWriteProperty,若只支持可读则继承ReadOnlyProperty

 此方式原理:

方式3:

在上面的基础之上还有另一种方式,可以根据属性的一些特征来返回一个合适的委托实现类,有点类似于抽象工厂模式,根据特定的需求返回合适的实现,如下:

class Test3{var text:String by StringDelegate()var text2:String by StringDelegate2()var text3:String by StringDelegateProvide()
}class StringDelegate{operator fun getValue(owner:Any,property:KProperty<*>):String{return "delegate value"}operator fun setValue(owner:Any,property:KProperty<*>,value:String){println("value:$value")}
}class StringDelegate2:ReadWriteProperty<Any,String>{override fun getValue(thisRef: Any, property: KProperty<*>): String {return "delegate value2"}override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {println("value2:$value")}}class StringDelegate3:ReadWriteProperty<Any,String>{override fun getValue(thisRef: Any, property: KProperty<*>): String {return "delegate value3"}override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {println("value3:$value")}}class StringDelegateProvide{operator fun provideDelegate(thisRef: Any,property: KProperty<*>):ReadWriteProperty<Any,String>{return if (property.name.contains("text3")){StringDelegate3()}else{StringDelegate2()}}
}fun main() {val t = Test3()println("text:${t.text}")t.text = "haha"println("text2:${t.text2}")t.text2 = "haha"println("text3:${t.text3}")
}

四、使用案例

通过委托封装Mmkv存取值的过程


import com.blankj.utilcode.util.GsonUtils
import com.tencent.mmkv.MMKV
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KPropertyopen class MMKVDelegate<T>(private val mmkv: MMKV,private val cls: Class<T>,private val key: String,private val defaultValue: T
) : ReadWriteProperty<Any?, T> {@Suppress("UNCHECKED_CAST")override fun getValue(thisRef: Any?, property: KProperty<*>): T {return when {cls.isEnum -> {val enumValues = cls.enumConstantsval enumValue = mmkv.decodeString(key, null)enumValues?.firstOrNull { it.toString() == enumValue } ?: defaultValue}cls.isData || MMKVDelegatedClass::class.java.isAssignableFrom(cls) -> runCatching {GsonUtils.fromJson(mmkv.decodeString(key), cls)}.getOrNull() ?: defaultValuecls.isAssignableFrom(String::class.java) -> mmkv.decodeString(key, defaultValue as String) as Tcls.isAssignableFrom(Int::class.java) -> mmkv.decodeInt(key, defaultValue as Int) as Tcls.isAssignableFrom(Boolean::class.java) -> mmkv.decodeBool(key, defaultValue as Boolean) as Tcls.isAssignableFrom(Float::class.java) -> mmkv.decodeFloat(key, defaultValue as Float) as Tcls.isAssignableFrom(Long::class.java) -> mmkv.decodeLong(key, defaultValue as Long) as Tcls.isAssignableFrom(Double::class.java) -> mmkv.decodeDouble(key, defaultValue as Double) as Tcls.isAssignableFrom(ByteArray::class.java) -> mmkv.decodeBytes(key, defaultValue as ByteArray) as Telse -> throw IllegalArgumentException("Unsupported type.")}}override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {val ok = when {cls.isEnum -> mmkv.encode(key, value?.toString())cls.isData || MMKVDelegatedClass::class.java.isAssignableFrom(cls) -> mmkv.encode(key,GsonUtils.toJson(value))cls.isAssignableFrom(String::class.java) -> mmkv.encode(key, value as String)cls.isAssignableFrom(Int::class.java) -> mmkv.encode(key, value as Int)cls.isAssignableFrom(Boolean::class.java) -> mmkv.encode(key, value as Boolean)cls.isAssignableFrom(Float::class.java) -> mmkv.encode(key, value as Float)cls.isAssignableFrom(Long::class.java) -> mmkv.encode(key, value as Long)cls.isAssignableFrom(Double::class.java) -> mmkv.encode(key, value as Double)cls.isAssignableFrom(ByteArray::class.java) -> mmkv.encode(key, value as ByteArray)else -> throw IllegalArgumentException("Unsupported type.")}if (!ok) {throw MMKVDelegateException.EncodeException()}}
}
import kotlin.jvm.internal.Reflectionval <T> Class<T>.isData: Boolean get() = Reflection.getOrCreateKotlinClass(this).isData

 假设我们在项目中需要在本地记录一些App行为信息

object AppBehavior {private const val TAG = "AppBehavior"private const val MMKV_ID = "AppBehavior"//记录App启动次数var appStartTime: Int by SettingValue(Int::class.java,Key.APP_START_TIME,0)/*** APP行为的属性委托* 值存储成功时,自动发送UserLocalSettingChangedEvent事件*  @param cls 属性的类型*  @param key 存储到MMKV的key*  @param defaultValue 从MMKV获取失败时,返回的默认值*/private class SettingValue<T>(private val cls: Class<T>,private val key: Key,private val defaultValue: T) : MMKVDelegate<T>(MMKV.mmkvWithID(MMKV_ID), cls, key.name, defaultValue) {override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {runCatching {super.setValue(thisRef, property, value)}.onFailure {Log.e(TAG, it.toString())if (it !is MMKVDelegateException) {throw it}}}}
}

调用:

AppBehavior.appStartTime++

相关文章:

kotlin 委托

一、类委托 interface DB{fun insert() } class SqliteDB : DB {override fun insert() {println(" SqliteDB insert")} }class MySql : DB{override fun insert() {println(" MySql insert")} }class OracleDB : DB{override fun insert() {println(&quo…...

Stream流的中间方法

一.Stream流的中间方法 注意1&#xff1a;中间方法&#xff0c;返回新的Stream流&#xff0c;原来的Stream流只能使用一次&#xff0c;建议使用链式编程 注意2&#xff1a;修改Stream流中的数据&#xff0c;不会影响原来集合或者数组中的数据 二.filter filter的主要用法是…...

【车载开发系列】ParaSoft单元测试环境配置(四)

【车载开发系列】ParaSoft单元测试环境配置&#xff08;四&#xff09; 【车载开发系列】ParaSoft单元测试环境配置&#xff08;四&#xff09; 【车载开发系列】ParaSoft单元测试环境配置&#xff08;四&#xff09;一. 如何设置过滤二. 如何设置静态扫描的规则三. 如何设置单…...

IDEA 设置自动定位文件

一、场景分析 IDEA 在使用的过程中&#xff0c;发现有时候&#xff0c;打开一个类&#xff0c;它并不能自动帮我们在左侧 Project 树中定位出文件&#xff0c;需要自己手动点击 瞄准 图标。很不方便。 二、解决方法 1、点击 瞄准 图标旁边的 竖三点 2、将 Alwasy Select Opene…...

Nature Machine Intelligence 基于强化学习的扑翼无人机机翼应变飞行控制

尽管无人机技术发展迅速&#xff0c;但复制生物飞行的动态控制和风力感应能力&#xff0c;仍然遥不可及。生物学研究表明&#xff0c;昆虫翅膀上有机械感受器&#xff0c;即钟形感受器campaniform sensilla&#xff0c;探测飞行敏捷性至关重要的复杂气动载荷。 近日&#xff0…...

[Web安全 网络安全]-XXE 外部实体注入攻击XML

文章目录&#xff1a; 一&#xff1a;前言 1.定义 1.1 XXE 1.2 XML可扩展标记语言 2.DDT文档类型定义 2.1 分类 2.2 元素element DTD元素 DTD属性 2.3 实体entity DTD实体类别 DTD实体声明引用 声明&#xff1a;内部 外部 参数实体 公共实体 引用&#xff1a;…...

8--苍穹外卖-SpringBoot项目中套餐管理 详解(二)

目录 删除套餐 需求分析和设计 代码开发 根据id查询套餐 mapper层 Service层 ServiceImpl层 Mapper层 批量删除套餐 mapper层 Service层 ServiceImpl层 Mapper层 SetmealMapper.xml 修改套餐 需求分析和设计 代码开发 起售停售套餐 需求分析和设计 代码开发…...

测试面试题:pytest断言时,数据是符点类型,如何断言?

在使用 Pytest 进行断言时&#xff0c;如果数据是浮点类型&#xff0c;可以使用以下方法进行断言&#xff1a; 一、使用pytest.approx pytest.approx可以用来比较两个浮点数是否近似相等。例如&#xff1a; import pytestdef test_float_assertion():result 3.14159expecte…...

Python与MongoDB交互

一、基本概念 MongoDB: 一个面向文档的数据库系统&#xff0c;使用BSON&#xff08;Binary JSON&#xff09;作为存储格式。集合&#xff08;Collection&#xff09;: 类似于关系型数据库中的表&#xff0c;是文档的集合。文档&#xff08;Document&#xff09;: MongoDB中的基…...

安卓AI虚拟女友项目开发的Android开发环境搭建

第五章&#xff1a;Android开发环境搭建与基础入门 5-1 项目讲解思路说明 本文是安卓AI数字虚拟人项目实战的第五章&#xff0c;开发安卓AI安卓版数字虚拟人的Android基础部分。 在本章中&#xff0c;我们将详细介绍如何搭建Android开发环境&#xff0c;包括Android Studio的…...

基于SpringBoot+Vue+MySQL的智能垃圾分类系统

系统展示 用户前台界面 管理员后台界面 系统背景 随着城市化进程的加速&#xff0c;垃圾问题日益凸显&#xff0c;不仅对环境造成污染&#xff0c;也给城市管理带来了巨大挑战。传统的垃圾分类方式不仅费时费力&#xff0c;而且手工操作容易出现错误&#xff0c;导致垃圾分类效…...

你的个人文件管理助手:AI驱动的本地文件整理工具

&#x1f310; 引言 在数字化时代&#xff0c;我们经常面临文件管理的挑战。电脑中的文件杂乱无章&#xff0c;寻找特定文件变得既费时又费力。幸运的是&#xff0c;现在有了一款名为本地文件整理器的神器&#xff0c;它利用AI技术帮助你快速、智能地整理文件&#xff0c;同时…...

【PyTorch】环境配置

框架介绍 Pytorch简介 2017年1月&#xff0c;FAIR&#xff08;Facebook AI Research&#xff09;发布了PyTorch。PyTorch是在Torch基础上用python语言重新打造的一款深度学习框架。Torch是采用Lua语言作为接口的机器学习框架&#xff0c;但因为Lua语言较为小众&#xff0c;导…...

枫叶MTS格式转换器- 强大、操作简单的MTS、M2TS视频转换工具供大家学习研究参考

一款功能强大、操作简单的MTS、M2TS视频转换工具,欢迎下载使用。 使用本MTS格式转换器可以帮助您将索尼和松下等摄像机录制的MTS、M2TS格式高清视频转换为其他流行的视频格式,如MP4、3GP、AVI、MPEG、WMV、ASF、MOV、RM、VCD、SVCD、DVD、MKV、FLV、SWF、MPG、MP3、WAV、WMA…...

Vscode把全部‘def‘都收起来的快捷键

在 VSCode 中&#xff0c;你可以使用以下快捷键来收起所有函数定义 (def)&#xff1a; Windows/Linux: Ctrl K, Ctrl 0macOS: Cmd K, Cmd 0 这个快捷键组合会折叠当前文件中所有的代码块&#xff08;包括所有函数和类定义&#xff09;。你可以通过相同的快捷键再次展开这…...

Web和UE5像素流送、通信教程

一、web端配置 首先打开Github地址&#xff1a;https://github.com/EpicGamesExt/PixelStreamingInfrastructure 找到自己虚幻引擎对应版本的项目并下载下来&#xff0c;我这里用的是5.3。 打开项目找到PixelStreamingInfrastructure-master > Frontend > implementat…...

【YOLO目标检测电梯间电动车与人数据集】共4321张、已标注txt格式、有训练好的yolov5的模型

目录 说明图片示例 说明 数据集格式&#xff1a;YOLO格式 图片数量&#xff1a;4321 标注数量(txt文件个数)&#xff1a;4321 标注类别数&#xff1a;2 标注类别名称&#xff1a;person、electricBicycle 数据集下载&#xff1a;电梯间电动车与人数据集 图片示例 数据…...

【网络安全】公钥基础设施

1. PKI 定义 1.1 公钥基础设施的概念 公钥基础设施&#xff08;Public Key Infrastructure&#xff0c;简称PKI&#xff09;是一种基于公钥密码学的系统&#xff0c;它提供了一套完整的解决方案&#xff0c;用于管理和保护通过互联网传输的信息。PKI的核心功能包括密钥管理、…...

云原生(四十一)| 阿里云ECS服务器介绍

文章目录 阿里云ECS服务器介绍 一、云计算概述 二、什么是公有云 三、公有云优缺点 1、优点 2、缺点 四、公有云品牌 五、市场占有率 六、阿里云ECS概述 七、阿里云ECS特点 阿里云ECS服务器介绍 一、云计算概述 云计算是一种按使用量付费的模式&#xff0c;这种模式…...

计算机网络:计算机网络体系结构 —— OSI 模型 与 TCP/IP 模型

文章目录 计算机网络体系结构OSI 参考模型TCP/IP 参考模型分层的必要性物理层的主要问题数据链路层的主要问题网络层的主要问题运输层的主要问题应用层的主要问题 分层思想的处理方法发送请求路由器转发接受请求发送响应接收响应 计算机网络体系结构 计算机网络体系结构是指将…...

SEO_避开这些常见误区让你的SEO效果事半功倍

<h2>SEO误区一&#xff1a;忽视关键词优化</h2> <p>在进行SEO优化时&#xff0c;关键词的选择和使用是至关重要的。很多人忽视了关键词优化&#xff0c;导致他们的网站在搜索引擎中的排名一直停滞不前。关键词不仅仅是为了让搜索引擎理解你的网站内容&#x…...

OpenClaw+QwQ-32B科研助手:文献摘要与笔记自动整理

OpenClawQwQ-32B科研助手&#xff1a;文献摘要与笔记自动整理 1. 为什么需要AI科研助手&#xff1f; 作为一名经常需要阅读大量文献的研究者&#xff0c;我发现自己长期陷入"文献管理困境"&#xff1a;下载的PDF堆积如山&#xff0c;重要信息散落在不同标注工具里&…...

vs code 实现source insight中的快捷键功能

1.自定义快捷键连续两组快捷键CtrlK CtrlS打开键盘快捷键定义界面修改向前向后的快捷键。ctrlu删除当前行复制当前行到下面2.增加bookmarks功能扩展部分装插件&#xff0c;定义快捷键ctrlm增加标签可以修改标签3.多行移动多行向上移动&#xff0c;向下移动Windows/Linux 用 Alt…...

Llama-3.2V-11B-cot开发者案例:基于Streamlit定制化UI扩展实践

Llama-3.2V-11B-cot开发者案例&#xff1a;基于Streamlit定制化UI扩展实践 1. 项目概述 Llama-3.2V-11B-cot是一款基于Meta Llama-3.2V-11B-cot多模态大模型开发的高性能视觉推理工具。该工具针对双卡4090环境进行了深度优化&#xff0c;特别修复了视觉权重加载的关键问题&am…...

数字中国新引擎:产业经济大脑的全景式解构与深度洞察(PPT)

“中国经济高质量发展的核心命题&#xff0c;已从‘有没有’转向‘好不好’。而要回答‘好不好’&#xff0c;就必须构建一套能看清、看准、看远的‘经济慧眼’。”在数字经济成为国家战略主战场的今天&#xff0c;地方政府正面临着前所未有的治理挑战&#xff1a;宏观政策如何…...

手把手教你用两块STM32F103C8T6实现CAN总线点对点通信(附完整代码)

从零开始实现STM32F103C8T6双板CAN总线通信实战指南 在嵌入式开发领域&#xff0c;CAN总线因其高可靠性和实时性成为工业控制、汽车电子等场景的首选通信协议。对于初学者而言&#xff0c;使用两块STM32F103C8T6开发板搭建CAN通信系统是掌握该技术的经典入门项目。本文将彻底拆…...

具身智能:千亿赛道崛起、多元场景落地与数据标注协同发展

2025被称为“具身智能元年”&#xff01; “具身智能” 也首次被写入中国《政府工作报告》&#xff0c;纳入国家战略规划&#xff0c;各地密集出台专项政策布局赛道。 数据标注作为具身智能涌现的核心基石&#xff0c;也同步完成了从劳动密集型向高技术专业化的范式升级。 具…...

第10章 RTOS 感知调试(OpenOCD)

第10章 RTOS 感知调试 导读:在嵌入式开发中,RTOS(实时操作系统)的使用非常普遍。然而当多个线程并发执行时,传统的单线程调试方式无法感知任务切换和线程上下文,给问题定位带来极大困难。OpenOCD 内置了对十余种主流 RTOS 的线程感知调试支持,能够在暂停目标时自动识别所…...

NCMDump解密工具:3步解锁网易云音乐加密文件,实现跨平台自由播放

NCMDump解密工具&#xff1a;3步解锁网易云音乐加密文件&#xff0c;实现跨平台自由播放 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗&#xff1f;NCMDump是一款专…...

精准获取与高效转换:基于burst2safe的哨兵SLC burst数据轻量化处理实践

1. 哨兵SLC burst数据处理的必要性 处理卫星遥感数据时&#xff0c;我们常常面临一个两难选择&#xff1a;要么下载整景数据占用大量存储空间&#xff0c;要么难以精准获取研究区域的小范围数据。以Sentinel-1卫星为例&#xff0c;单景解压后的SLC数据可达7GB&#xff0c;而实际…...