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

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中可以给一个类添加一个新的方法而不用继承该类或者使用设计模式&#xff0c;这样的方法称为扩展。 1.扩展函数 声明一个扩展函数&#xff0c;我们需要用一个 接收者类型 也就是被扩展的类型来作为他的前缀。 下面代码为 MutableList 添加一个swap 函数&am…...

QT入门Containers之Widget、Frame

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

数据结构与算法基础-学习-12-线性表之顺序队

一、个人理解队列是线性表的衍生之一&#xff0c;具有先进先出的特性&#xff0c;在队尾进行插入操作&#xff0c;在队头进行删除操作。队列的存储结构分为两个大类&#xff0c;一种是顺序队&#xff0c;就是用数组实现。另一种就是链队&#xff0c;使用链表实现。顺序队存在真…...

Python 字典(Dictionary)小窍门

字典是另一种可变容器模型&#xff0c;且可存储任意类型对象。字典的每个键值 key:value 对用冒号 : 分割&#xff0c;每个键值对之间用逗号 , 分割&#xff0c;整个字典包括在花括号 {} 中 ,格式如下所示&#xff1a;d {key1 : value1, key2 : value2 }注意&#xff1a;dict …...

知识图谱构建技术综述

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

环境变量和进程地址空间

目录 环境变量&#xff1a; env&#xff1a;显示所有的环境变量&#xff1a; echo $环境变量名表示查看环境变量的值 理解环境变量&#xff1a; getenv&#xff1a;显示环境变量的值 export set命令&#xff1a;显示所有变量 unset取消变量&#xff1a; pwd&#xff1a;当…...

【数据结构】栈和队列

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

sql复习(视图、Top-N分析、其他数据库对象)

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

2023年私募股权基金研究报告

第一章 概况 PE是私募&#xff0c;也即私募投资基金&#xff0c;是指以非公开发行方式向合格投资者募集的&#xff0c;投资于股票、股权、债券、期货、期权、基金份额及投资合同约定的其他投资标的&#xff08;如艺术品、红酒等&#xff09;的投资基金&#xff0c;简称私募基金…...

Redis单点故障+红锁原理

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、Redis单点故障二、红锁原理三、Redission实现了红锁一、Redis单点故障 单台redis容易出单点故障采用集群,获取到锁之后数据持久化到rdb,aof文件中从节点有可能在从主节点拿到数据之前,主节点…...

数据库中的存储过程

1、创建存储过程create procedure sp_name[参数名] [类型],[参数名] [类型]asbegin.........end以上格式还可以简写成&#xff1a;create proc sp_name[参数名] [类型],[参数名] [类型]asbegin.........end/*注&#xff1a;“sp_name”为需要创建的存储过程的名字&#xff0c;该…...

基于 VPX 总线的工件台运动控制系统研究与开发-DSP+FPGA硬件架构(一)

作为光刻机核心单元之一&#xff0c;超精密工件台主要负责实现快速扫描、上下片、精密定位、调平调焦等功能。目前&#xff0c;较为成熟的方案大多采用 VME 并行总线架构来建立超精密工件台控制系统&#xff0c;由于随着系统性能要求的提升&#xff0c;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&#xff0c;创建许可证3、setup.py文件4.克隆setup.py仓库&#xff08;推荐&#xff09;2.3 编写核心代码2.4 生成分发档案2.5 发布包到PyPi3.验证发布PYPI成功…...

【Git】git常用命令总结

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

Cortex-M0中断控制和系统控制

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

科技云报道:2023,云计算的风向变了

科技云报道原创。 2022&#xff0c;是云计算的“分水岭”之年。 与前两年的火热相比&#xff0c;2022年云计算行业实属不太好过&#xff1a;阿里云一季度营收增速创出历史新低&#xff0c;腾讯云的市场份额也被后来者华为云反超&#xff0c;沦为第三。 在此情形下&#xff0c…...

工程管理系统源码-专注项目数字化管理-工程管理

工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#xff1a;实现对数据字典标签的增删改查操作 2、编码管理&#xff1a;实现对系统编码的增删改查操作 3、用户管理&#xff1a;管理和查看用户角色 4、菜单管理&#xff1a;实现对系统菜单的增删改查操…...

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题 遭受干旱侵袭的植物群落 背景 不同种类的植物对压力的反应方式不同。例如&#xff0c;草原对干旱非常敏感。干旱发生的频率和严重 程度各不相同。大量的观察表明&#xff0c;不同物种的数量在植物群落如何适应连续几代的干旱周期中 起着重要作用。在一些只有一种植物的…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看

文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

HTML前端开发:JavaScript 获取元素方法详解

作为前端开发者&#xff0c;高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法&#xff0c;分为两大系列&#xff1a; 一、getElementBy... 系列 传统方法&#xff0c;直接通过 DOM 接口访问&#xff0c;返回动态集合&#xff08;元素变化会实时更新&#xff09;。…...

React核心概念:State是什么?如何用useState管理组件自己的数据?

系列回顾&#xff1a; 在上一篇《React入门第一步》中&#xff0c;我们已经成功创建并运行了第一个React项目。我们学会了用Vite初始化项目&#xff0c;并修改了App.jsx组件&#xff0c;让页面显示出我们想要的文字。但是&#xff0c;那个页面是“死”的&#xff0c;它只是静态…...