Kotlin新手教程五(扩展)
一、扩展
在Kotlin中可以给一个类添加一个新的方法而不用继承该类或者使用设计模式,这样的方法称为扩展。
1.扩展函数
声明一个扩展函数,我们需要用一个 接收者类型 也就是被扩展的类型来作为他的前缀。 下面代码为 MutableList 添加一个swap 函数:
fun MutableList<Int>.swap(index1: Int, index2: Int) {val tmp = this[index1] // “this”对应该列表this[index1] = this[index2]this[index2] = tmp
}
这个 this 关键字在扩展函数内部对应到接收者对象(传过来的在点符号前的对象) 现在,我们对任意 MutableList 调用该函数了:
val list = mutableListOf(1, 2, 3)
list.swap(0, 2) // “swap()”内部的“this”会保存“list”的值
我们也可以使用泛型进一步升级它:
fun <T> MutableList<T>.swap(index1: Int, index2: Int) {val tmp = this[index1] // “this”对应该列表this[index1] = this[index2]this[index2] = tmp
}
2.扩展是静态解析的
扩展听起来很强大,但实际不是真正的修改他们所拓展的类,仅仅是可以通过使用该类型的变量用点表达式调用新函数。例:
fun main(args: Array<String>) {val b=B()println(b.getName())
}
open class A
class B:A()
fun A.getName()="A"
fun B.getName()="B"
输出结果为B;这个例子中B为A的子类,且都给两个类拓展了同名方法getName,但是输出结果为何是B。这就是因为扩展函数式静态分发的:调用的扩展函数是由函数调用所在的表达式的类型来决定的, 而不是由表达式运行时求值结果决定的。
当扩展函数和类中原有的函数一致时,最终会调用成员函数:
fun main(args: Array<String>) {val a = A()a.myFun()
}class A {fun myFun() {println("A")}
}fun A.myFun() {println("花里胡哨")
}
输出结果为A
但是如果方法名相同,参数列表不同,就相当于方法重载,就是传入参数符合哪个运行哪个
3.可空接受者
注意可以为可空的接收者类型定义扩展。这样的扩展可以在对象变量上调用, 即使其值为 null,并且可以在函数体内检测 this == null,这能让你在没有检测 null 的时候调用 Kotlin 中的toString():检测发生在扩展函数的内部。
fun Any?.toString(): String {if (this == null) return "null"// 空检测之后,“this”会自动转换为非空类型,所以下面的 toString()// 解析为 Any 类的成员函数return toString()
}
4.扩展属性
与函数一样,属性也可以进行扩展,但是由于扩展没有将实际的成员变量插入类中,因此对扩展属性来说幕后字段是无效的。
5.伴生对象的扩展
如果一个类定义有一个伴生对象 ,你也可以为伴生对象定义扩展函数与属性。就像伴生对象的常规成员一样, 可以只使用类名作为限定符来调用伴生对象的扩展成员:
class MyClass {companion object { } // 将被称为 "Companion"
}fun MyClass.Companion.printCompanion() { println("companion") }fun main() {MyClass.printCompanion()
}
6.扩展的作用域
大多数时候我们在顶层定义扩展——直接在包里:
package org.example.declarationsfun List<String>.getLongestString() { /*……*/}
要使用所定义包之外的一个扩展,我们需要在调用方导入它:
package org.example.usageimport org.example.declarations.getLongestStringfun main() {val list = listOf("red", "green", "blue")list.getLongestString()
}
7.扩展声明为成员
fun main(args: Array<String>) {Connection(Host("aaa"),443).connect()
}class Host(val hostname: String) {fun printHostname() {println(hostname)}
}
class Connection(val host: Host,val port: Int){fun printPort(){println(port)}fun Host.printConnectionString(){printHostname()print(":")printPort()}fun connect(){host.printConnectionString()}
}
上例中在Connection类中扩展了Host的方法,所以调用该类的扩展方法时能够使用,但是如果调用Host(“kotl.in”).printConnectionString(443)则会报错。
对于分发接收者与扩展接收者的成员名字冲突的情况,扩展接收者优先。要引用分发接收者的成员你可以使用 限定的 this 语法。
class Connection {fun Host.getConnectionString() {toString() // 调用 Host.toString()this@Connection.toString() // 调用 Connection.toString()}
}
声明为成员的扩展可以声明为 open 并在子类中覆盖。这意味着这些函数的分发对于分发接收者类型是虚拟的,但对于扩展接收者类型是静态的。
open class Base { }class Derived : Base() { }open class BaseCaller {open fun Base.printFunctionInfo() {println("Base extension function in BaseCaller")}open fun Derived.printFunctionInfo() {println("Derived extension function in BaseCaller")}fun call(b: Base) {b.printFunctionInfo() // 调用扩展函数}
}class DerivedCaller: BaseCaller() {override fun Base.printFunctionInfo() {println("Base extension function in DerivedCaller")}override fun Derived.printFunctionInfo() {println("Derived extension function in DerivedCaller")}
}fun main() {BaseCaller().call(Base()) // “Base extension function in BaseCaller”DerivedCaller().call(Base()) // “Base extension function in DerivedCaller”——分发接收者虚拟解析DerivedCaller().call(Derived()) // “Base extension function in DerivedCaller”——扩展接收者静态解析
}
上一篇:Kotlin新手教程四(抽象类和接口)
相关文章:
Kotlin新手教程五(扩展)
一、扩展 在Kotlin中可以给一个类添加一个新的方法而不用继承该类或者使用设计模式,这样的方法称为扩展。 1.扩展函数 声明一个扩展函数,我们需要用一个 接收者类型 也就是被扩展的类型来作为他的前缀。 下面代码为 MutableList 添加一个swap 函数&am…...

QT入门Containers之Widget、Frame
目录 一、QWidget界面相关 1、布局介绍 2、基本界面属性 3、特殊属性 二、QFrame 三、Demo展示 此文为作者原创,创作不易,转载请标明出处! 一、QWidget界面相关 1、布局介绍 为什么将QWidget容器放在第一个,因为目前使用过…...

数据结构与算法基础-学习-12-线性表之顺序队
一、个人理解队列是线性表的衍生之一,具有先进先出的特性,在队尾进行插入操作,在队头进行删除操作。队列的存储结构分为两个大类,一种是顺序队,就是用数组实现。另一种就是链队,使用链表实现。顺序队存在真…...
Python 字典(Dictionary)小窍门
字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值 key:value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中 ,格式如下所示:d {key1 : value1, key2 : value2 }注意:dict …...

知识图谱构建技术综述
摘要 *知识图谱为实现语义化智能搜索以及知识互联打下了基础,。, *随着知识的发展,传统的基于模板和规则构建的知识图谱已经被深度学习所替代。 知识组织得原则中:知识的充分性、有序性和标准化规则。深度学习的效果在很大程度上…...

环境变量和进程地址空间
目录 环境变量: env:显示所有的环境变量: echo $环境变量名表示查看环境变量的值 理解环境变量: getenv:显示环境变量的值 export set命令:显示所有变量 unset取消变量: pwd:当…...

【数据结构】栈和队列
目录 一、栈 1、栈的定义 2、栈的模拟实现(顺序栈) 1、创建一个顺序结构的栈 2、实现压栈方法(push) 3、模拟实现pop方法(出栈) 4、模拟实现peek(查看) 5、测试上述方法 3、栈的应用场景 1、改变元…...

sql复习(视图、Top-N分析、其他数据库对象)
一、视图view 1.视图定义 视图是一种虚表。 视图建立在已有表的基础上, 视图赖以建立的这些表称为基表。 向视图提供数据内容的语句为 SELECT 语句, 可以将视图理解为存储起来的 SELECT 语句。 视图向用户提供基表数据的另一种表现形式。 2.使用视图的好处 控制数据访问 简…...

2023年私募股权基金研究报告
第一章 概况 PE是私募,也即私募投资基金,是指以非公开发行方式向合格投资者募集的,投资于股票、股权、债券、期货、期权、基金份额及投资合同约定的其他投资标的(如艺术品、红酒等)的投资基金,简称私募基金…...
Redis单点故障+红锁原理
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、Redis单点故障二、红锁原理三、Redission实现了红锁一、Redis单点故障 单台redis容易出单点故障采用集群,获取到锁之后数据持久化到rdb,aof文件中从节点有可能在从主节点拿到数据之前,主节点…...
数据库中的存储过程
1、创建存储过程create procedure sp_name[参数名] [类型],[参数名] [类型]asbegin.........end以上格式还可以简写成:create proc sp_name[参数名] [类型],[参数名] [类型]asbegin.........end/*注:“sp_name”为需要创建的存储过程的名字,该…...

基于 VPX 总线的工件台运动控制系统研究与开发-DSP+FPGA硬件架构(一)
作为光刻机核心单元之一,超精密工件台主要负责实现快速扫描、上下片、精密定位、调平调焦等功能。目前,较为成熟的方案大多采用 VME 并行总线架构来建立超精密工件台控制系统,由于随着系统性能要求的提升,VME 总线以及相应的处理器…...
Android 9.0 根据包名授予app所需的权限
1.概述 在9.0的系统rom产品定制化开发中,在对系统app首次启动默认是会弹出授权的弹窗的,但是对于产品来说会显示的有些麻烦,对产品体验度也不是很好,所以在进行产品开发的时候,默认要求对一些app根据包名授予权限,这样就不会弹出授权的窗口了默认就有权限了,接下来就来实…...
如何将Python包发布到PyPI上,使用pip安装自己的库
如何发布自己的第三方库1. PyPi的用途2.Python包发布步骤2.1 创建目录结构2.2 准备文件1、README.rst2、LICENSE.txt,创建许可证3、setup.py文件4.克隆setup.py仓库(推荐)2.3 编写核心代码2.4 生成分发档案2.5 发布包到PyPi3.验证发布PYPI成功…...

【Git】git常用命令总结
简言 git是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。 里面有很多常用的命令语法,在此做一个常用命令总结记录,以备不时之需。 命令总结 由于git是基于linux开发的工具,所以有个特点&a…...

Cortex-M0中断控制和系统控制
目录1.NVIC和系统控制块特性2.中断使能和清除使能3.中断挂起和清除挂起4.中断优先级5.中断控制的通用汇编代码使能和禁止中断设置和清除中断挂起状态设置中断优先级6.异常屏蔽寄存器(PRIMASK)7.中断输入和挂起行为8.中断等待9.系统异常的控制寄存器10.系…...

科技云报道:2023,云计算的风向变了
科技云报道原创。 2022,是云计算的“分水岭”之年。 与前两年的火热相比,2022年云计算行业实属不太好过:阿里云一季度营收增速创出历史新低,腾讯云的市场份额也被后来者华为云反超,沦为第三。 在此情形下,…...
工程管理系统源码-专注项目数字化管理-工程管理
工程项目各模块及其功能点清单 一、系统管理 1、数据字典:实现对数据字典标签的增删改查操作 2、编码管理:实现对系统编码的增删改查操作 3、用户管理:管理和查看用户角色 4、菜单管理:实现对系统菜单的增删改查操…...

Nacos详细使用操作文档(图文详细)
文章目录Nacos详细使用操作文档(图文详细)1、安装2、Nacos作为注册中心2.1、Nacos服务注册【ICRMS】2.2、Nacos 服务调用2.2.1、Feign 远程调用【Personnel】2.2.2)、RestTemplateRibbon 远程调用【Personnel】3、Nacos作为配置中心4、Nacos 命令空间5、Nacos配置文件参数详解N…...
如何评价2023年美赛ABC题目
A题 遭受干旱侵袭的植物群落 背景 不同种类的植物对压力的反应方式不同。例如,草原对干旱非常敏感。干旱发生的频率和严重 程度各不相同。大量的观察表明,不同物种的数量在植物群落如何适应连续几代的干旱周期中 起着重要作用。在一些只有一种植物的…...

Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...