Kotlin 特性之扩展函数

news2024/9/25 19:22:59

什么是扩展函数

扩展函数是 Java 不具备的,而 Kotlin 独有的特性,在日常开发中使用频率很高,类似于设计模式中的装饰模式,其作用就是在不改变原有类的情况下,扩展新的功能。

如何使用扩展函数和扩展属性

扩展函数的基本使用

在需要被扩展的类或者接口后面添加方法即可,下面是一个给 Int 类型扩展了一个判断是否是偶数的方法的例子,在扩展函数里使用 this 指代被扩展的类或者接口的实例对象:

/**
 * 是否是偶数,用与运算取出最后一位,最后一位为0则是偶数
 */
fun Int.isEven(): Boolean {
    return (this and 1) == 0
}

使用的时候,对于任意一个 Int 型数据都可以直接调用 isEven() 方法。

2.isEven() //得到返回值true
扩展属性的基本使用

扩展属性实际上是提供一种方法来访问属性而已,并且这些扩展属性是没有任何的状态的,因为不可能给被扩展的类或者接口的对象额外添加属性字段,只是使用简洁语法类似直接操作属性,实际上还是方法的访问。例如给 TextView 扩展一个属性表示是否是粗体:

//扩展属性定义
var TextView.isBolder: Boolean
	get() {
		return this.paint.isFakeBoldText
	}
	set(value) {
		this.paint.isFakeBoldText = value
	}

在扩展属性中也是使用 this 指代被扩展的类或者接口的实例对象。另外必须定义 get() 方法,在 Kotlin 中类中的属性都是默认添加 get() 方法的,但是由于扩展属性并不是给现有类添加额外的属性,自然就没有默认 get() 方法实现了,所以必须手动添加 get() 方法。至于 set() 方法,就看属性是否可变了,也就是该扩展属性对应是 var 还是 val 了。

什么是顶层函数

在解析扩展函数的本质之前,先来了解一下 Kotlin 的另一个特性 – 顶层函数。

在 Java 中有静态方法和静态属性,一般是为了提供全局共享访问的方法和属性,是独立于对象之外的。静态方法和静态属性需要在类中声明,在使用的时候也是通过 类名.方法名 或者 类名.属性名 的方式访问。静态函数内部是不包含状态的,也就是所谓的纯函数,它的输入仅仅来自于它的参数列表,而它的输出也仅仅依赖于它参数列表,静态函数所在的类只是作为一个容器的角色。

在 Kotlin 中认为一个函数有时候并不需要属于任何一个类,它可以独立存在。所以在 Kotlin 中类似静态函数和静态属性可以去掉外层类的容器,一个函数或者属性可以直接定义在一个 Kotlin 文件的顶层中,在使用的地方只需要 import 这个函数或属性即可,这就是顶层函数。

顶层函数的使用

首先,创建一个文件,这里文件取名为 TopFunction:
创建文件

然后在文件中定义函数,这里定义了一个判断 Int 数字是否是偶数的函数:

/**
 * 是否是偶数,用与运算取出最后一位,最后一位为0则是偶数
 */
fun isEven(num: Int): Boolean {
    return (num and 1) == 0
}

需要使用的时候直接调用函数即可:

isEven(2) //得到返回值true

定义并使用一个顶层函数很简单,但是顶层函数究竟是怎么运行在 JVM 中的呢?如果是 Java 和 Kotlin 混合开发模式,在 Kotlin 中定义的顶层函数,在 Java 中又是怎么调用的呢?

顶层函数的本质

通过 decompile 看下反编译后对应的 Java 代码:

public final class TopFunctionKt {
   public static final boolean isEven(int num) {
      return (num & 1) == 0;
   }
}
  • 顶层文件会反编译成一个容器类。(类名默认为顶层文件名+"Kt"后缀)
  • 顶层函数会反编译成一个 static 静态函数。

所以顶层函数本质就是 Java 中的静态函数。如果需要在 Java 中调用 Kotlin 中的顶层函数,方式很简单,就是利用反编译生成的类作为静态函数容器类直接调用对应的函数,例如上面的顶层函数在 Java 中调用写法,TopFunctionKt.isEven(int num)。

注意: 顶层文件反编译成的 Java 中的容器类名默认是顶层文件名+“Kt”后缀,但是也是可以自定义的。也就是说顶层文件名和生成容器类名没有必然的联系。通过 Kotlin 中的 @file: JvmName(“自定义生成类名”) 注解就可以自动生成对应 Java 调用类名,注意需要放在文件顶部,在package声明的前面。这样 Java 调用自定义类名顶层函数就更加自然,一般建议使用注解修改类名。

扩展函数的本质

扩展函数也是不属于任何一个类,独立存在于 Kotlin 文件中,是不是和顶层函数一样,本质是 Java 中的静态函数呢?答案是肯定的。

/**
 * 是否是偶数,用与运算取出最后一位,最后一位为0则是偶数
 */
fun Int.isEven(): Boolean {
    return (this and 1) == 0
}

我们将上述扩展函数写在文件名为 SpreadFunction 的文件中,通过 decompile 看下反编译后对应的 Java 代码:

public final class SpreadFunctionKt {
   public static final boolean isEven(int $this$isEven) {
      return ($this$isEven & 1) == 0;
   }
}

跟顶层函数如出一辙,扩展函数本质就是 Java 中的静态函数,被扩展的类或者接口的实例对象会作为函数参数,用 this 指代。同样的,在 Java 中调用 Kotlin 中的扩展函数也是一样的方式,不同的地方是需要插入一个被扩展的类或者接口的实例对象。

扩展属性实际上就是提供某个属性访问的set,get方法,set,get方法本质都是静态函数,同时都会传入一个被扩展类的对象,然后在其内部用这个实例对象去访问和修改对象所对应的类的属性,在此就不细说了。

扩展函数与成员函数

  1. 扩展函数和成员函数都可以访问被扩展类的公有方法和属性。
  2. 扩展函数不能访问被扩展类的私有方法和属性,成员函数可以访问类中的私有方法和属性。
  3. 父类成员函数可以被子类重写,但扩展函数不可以被子类重写。

理解了扩展函数的本质是一个静态函数,且处于类的外部,被扩展类的实例对象作为函数参数传入,就可以很好地理解扩展函数与成员函数之间的共同性和差异性了。扩展函数通过实例对象进行访问自然不能访问类中的私有方法和属性,但可以访问类中的公有方法和属性。扩展函数处于类的外部,并不是类的一部分,不会被子类所继承,自然不可以被子类重写。

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

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

相关文章

通信工程学习:什么是ASK振幅键控、FSK频移键控、PSK相移键控

ASK振幅键控、FSK频移键控、PSK相移键控 ASK(振幅键控)、FSK(频移键控)和PSK(相移键控)是三种常见的数字调制技术,它们各自通过不同的方式改变载波的某个参数来传输数字信息。以下是对这三种调制…

微软 Power Apps MDA 模型驱动应用解决Image字段查询出来缩略图问题变原图方法(c#+Plugin方式)

微软 Power Apps MDA 模型驱动应用解决Image字段查询出来缩略图问题变原图方法(c#Plugin方式) 在某些特定的场景中,需要将Image字段中的图片取出来,一般来说直接查询这个字段可以直接取,取出来的就是一个Base64格式的图…

【linux-Day2】linux下的基本指令

【linux-Day2】linux下的基本指令 一键查看操作系统的重要地位linux下的基本指令📢ls:显示当前目录下所有的子目录和文件📢pwd:显示用户当前所在的目录,在windows中,相当于显示当前目录的绝对路径。&#x…

推理与训练,分布式训练

什么是推理training 在人工智能领域,推理是指经过训练的机器学习模型从全新的数据(输入)中得出结论(输出)的过程。通俗地讲,推理是模型的实际运行。 什么是训练 inference 在人工智能领域,训…

Linux内核初始化过程中加载TCP/IP协议栈

Linux内核初始化过程中加载TCP/IP协议栈 Linux内核初始化过程中加载TCP/IP协议栈,从start_kernel、kernel_init、do_initcalls、inet_init,找出Linux内核初始化TCP/IP的入口位置,即为inet_init函数。 Linux内核启动过程 之前的实验中我们设…

差值图中像素总和的正负性(极性)含义

1. 正总和的含义 当 I1 减去 I2 的差值图总和为正时,这意味着整体上 I1 的像素值比 I2 高。即: 表示: 2. 局部亮度变化 即便差值图的总和为正,也不能确保 I1 在所有区域都比 I2 亮。差值图的正总和只是表明在整个图像中&#xf…

webpack5 创建多页面应用配置

简单版webpack创建多页面应用,只要把配置文件复制下来,然后npm安装相应插件,正常是能跑起来了 创建 初始化 npm init生成package.json文件安装webpack npm i -D webpack webpack-cli webpack-dev-server创建main.js入口文件和webpack.config…

云计算实训48——k8s环境搭建(详细版)

1.创建主机、设置ip、设置hostname 2.设置免密登录 # 生成私钥 [rootk8s-master ~]# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): /root/.ssh/id_rsa already exists. Overwrite (y/n)? y Enter passphr…

智能化转型的基石:精心策划楼宇自控系统的选择与部署

智能化转型的基石:精心策划楼宇自控系统的选择与部署 在智慧城市的宏伟蓝图中,建筑智能化已成为推动城市进步的强劲动力。楼宇自控系统,作为这一进程中的核心组件,其选择与部署策略不仅关乎建筑内部的运营效率与能源管理&#xff…

十大排序算法的特点及应用场景

一.十大经典排序算法介绍 1. 冒泡排序(Bubble Sort) 原理:通过重复遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复进行的,直到没有再需要交换的元素为止。…

视频编辑SDK解决方案,完整的前端代码+SDK功能交付

繁琐的视频编辑过程往往成为创作者们提升作品质量的瓶颈,美摄科技凭借其深厚的AI技术积累与创新的移动端视频编辑SDK解决方案,正引领着视频编辑领域的新潮流,让每一位创作者都能轻松驾驭创意,实现从灵感闪现到作品呈现的无缝对接。…

点餐小程序实战教程05登录界面搭建

目录 1 设置tab栏2 添加页面3 搭建登录界面3.1 显示头像3.2 显示昵称3.3 注册按钮 总结 上一篇我们讲解了如何在首页加载的时候获取用户信息,一般小程序会在底部放置tab栏,将不同的菜单放置在tab栏中。我们的用户注册逻辑是,如果用户点击了底…

Java码农人生开启手册——多态与重写

一、多态 概念:通俗来说,就是多种形态;具体点,就是去完成某个行为,当不同的对象去完成时会产生不同的状态。 1、多态的实现条件 三个条件,缺一不可: 必须在继承体系下子类必须对父类中方…

训练 Vision Transformer 模型并运行推理

目录 CV Architecture ViT and U-Net Training ViT Florence-2 Load Model Load images CV Scenarios test Genarate CAPTION from the images DENSE REGION CAPTION and REGION_PROPOSA Caption to Phrase Grounding Bounding boxes OCR test Fine Tuning Floren…

2024年转行做网络安全工程师还来得及吗?薪资怎么样呢

🤟 基于入门网络安全/黑客打造的:👉黑客&网络安全入门&进阶学习资源包 2022年以来,我国网络安全行业的市场规模持续增长,根据市场调研在线网发布的2023-2029年中国网络安全集成行业市场运行态势及发展趋向分析…

Pycharm配置ssh远程服务器解析器

算法学习、4对1辅导、论文辅导或核心期刊可以通过公众号滴滴我 文章目录 需求配置流程 需求 之前在开发中,Pycharm都是通过本机Python环境来解析。但有时候,可能受限于本机电脑配置原因,导致运行速度并不快。因此推荐大家尝试下&#xff0c…

一文带你彻底掌握二分查找

1. 认识二分查找 二分查找也被称为折半查找,他是一种查询效率较高的查找方式,普通查找的方式通常是从头到尾遍历一遍数组,二分查找的方式是找到数组中间的那个元素mid与目标值target进行比较,比target小就去前半段找,…

Java中List集合去重

反问问题:为什么不直接使用 Set 或者 LinkedHashSet 呢 实际场景:实际的业务开发中遇到的情况会更复杂。比如,List 集合可能是历史遗留问题,也有可能是调用接口返回的类型限制,只能使用 List 接收,又或者是…

Qualcomm Linux 交叉编译应用程序

1. 前提条件 Ubuntu 20.04 系统 Qualcomm RB3 Gen2开发板 2.下载并安装 eSDK 平台 1.从 Qualcomm 发布存档平台下载 eSDK。 wget https://artifacts.codelinaro.org/artifactory/qli-ci/flashable-binaries/qimpsdk/qcm6490/x86/qcom-6.6.28-QLI.1.1-Ver.1.1_qim-product-s…

消除数字球-第15届蓝桥省赛Scratch初级组真题第5题

[导读]:超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成,后续会不定期解读蓝桥杯真题,这是Scratch蓝桥杯真题解析第184讲。 如果想持续关注Scratch蓝桥真题解读,可以点击《Scratch蓝桥杯历年真题》并订阅合集,…