文章目录

  • I . 扩展函数 总结
  • II . 扩展函数概念简介
  • III . 扩展函数简单示例
  • IV . 扩展函数调用选择方式 : 静态解析
  • V . 扩展函数 调用优先级
  • VI . 扩展函数 接收者 空值处理

I . 扩展函数 总结


扩展函数总结 :

① 扩展函数定义方式 : fun 接收者类型.函数名(参数列表){函数体}

② 扩展函数调用方式 : 父类和子类定义了相同函数签名的扩展函数 , 根据变量声明的类型调用对应的扩展函数 , 不根据变量的实际类型调用 ;

③ 扩展函数与成员优先级对比 : 成员函数优先级高于扩展函数 , 相同签名的两个函数 , 优先调用成员函数 ;

④ 可空接收者类型 : 可以为可空类型的接收者定义扩展函数 , 即声明扩展函数和调用扩展函数的类型后面都必须有 ? 修饰 ; ( 注意空值判定处理 )

II . 扩展函数概念简介


1 . 扩展函数声明格式 : 扩展函数在函数前多了接收者类型 , 函数体中可以使用 this 调用 接收者类型对象中的成员 ;

fun 接收者类型.扩展函数名 ( 扩展函数参数列表 ) {//扩展函数函数体 , 可使用 this 关键字调用对象中的成员
}

2 . 接收者类型 : 声明扩展函数时 , 需要指定该函数是为哪个类型扩展的 , 被扩展的类型就是接收者类型 ;

3 . 调用接收者类型对象成员 : 在函数体中使用 this 关键字 , 可以调用接收者类型对象中的成员 , 如在下面的示例中 , 在类外部的扩展函数中 , 调用 Student 对象中的 name 成员 , 可以使用 this.name ;

4 . 扩展函数本质 : 为 接收者类型 定义扩展函数 , 并没有真正的再改类中插入新的成员函数 , 仅能通过 接收这类型对象变量.扩展函数() 的方式来调用这个函数 ;

III . 扩展函数简单示例


扩展函数代码示例 :

① 接收者类型扩展 : 为已经定义好的 Student 类 , 定义一个扩展函数 print ;

② 扩展函数参数 : 该扩展函数传入一个 num : Int 参数 ;

③ this 关键字访问接收者类型对象成员 : 在扩展函数中使用 this 关键字访问 Student 类成员 , this.name 访问其 name 属性 , this.age 访问其 age 属性 ;

class Student {var name : String = "Tom"var age : Int = 18
}/*为 Student 类定义扩展函数接收者类型 : Student类型名称 : print参数列表 : num : Intthis 关键字 :使用 this 关键字可以在扩展函数中访问对象中的成员 ( 注意可见性 )*/
fun Student.print(num : Int){println("打印学生信息 : 姓名 : ${this.name}, 年龄 : ${this.age}, 学号 : ${num}")
}fun main() {//调用 Student 对象的扩展函数var student = Student();//打印学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 1student.print(1)
}

④ 执行结果 :

打印学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 1

IV . 扩展函数调用选择方式 : 静态解析


1 . 扩展函数定义 : 为 基类 和 派生类 分别定义相同签名的扩展函数 , 可以精确控制调用 基类 或 派生类 的扩展函数 ;

2 . 调用方式 : 根据接收者类型确定调用哪个扩展函数 ;

① 接收者类型基类 : 如果 接收者类型 声明为基类 , 那么就会调用基类的扩展函数 ;

② 这里注意 : 不管其值被赋值成基类对象 , 还是赋值成派生类对象 , 接收者类型被声明成基类类型 , 调用的扩展函数就是基类的扩展函数 ;

③ 接收者类型派生类 : 如果 接收者类型 声明为派生类 , 那么就会调用派生类的扩展函数 ;

3 . 代码示例 :

① 定义父类与子类 : 定义父类 Student , 子类 MaleStudent ;

② 分别为父类 , 子类定义扩展函数 : 为 Student 和 MaleStudent 分别定义 print(num : Int){} 扩展函数 ;

③ 扩展函数调用 : 只要类型声明成 Student 类型 , 那么其调用的扩展函数就是 Student.print(num : Int){} 扩展函数 , 不管该类型的对象是父类还是子类对象 ; 只要类型声明成 MaleStudent 类型 , 那么其调用的扩展函数就是 MaleStudent.print(num : Int){} 扩展函数

//定义父类
open class Student {var name : String = "Tom"var age : Int = 18
}//定义子类
class MaleStudent : Student(){}//父类扩展函数
fun Student.print(num : Int){println("打印学生信息 : 姓名 : ${this.name}, 年龄 : ${this.age}, 学号 : ${num}")
}//子类扩展函数
fun MaleStudent.print(num : Int){println("打印男学生信息 : 姓名 : ${this.name}, 年龄 : ${this.age}, 学号 : ${num}")
}fun main() {// 1 . 变量声明为父类类型 , 赋值父类对象//接收者类型声明为 Student , 但实际对象是 Student 类型的//  此时扩展函数调用 Student 接收类型 的扩展数据var student : Student = Student();//打印学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 1student.print(1)// 2 . 变量声明为父类类型 , 赋值子类对象//接收者类型声明为 Student , 但实际对象是 MaleStudent 类型的//  此时扩展函数调用 Student 接收类型 的扩展函数var maleStudent : Student = MaleStudent()//打印学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 2maleStudent.print(2)// 3 . 变量声明为子类类型 , 赋值子类对象//接收者类型声明为 MaleStudent , 实际对象是 MaleStudent 类型的//  此时扩展函数调用 MaleStudent 接收类型 的扩展函数var maleStudent2 : MaleStudent = MaleStudent()//打印男学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 3maleStudent2.print(3)
}

执行结果 :

打印学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 1
打印学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 2
打印男学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 3

V . 扩展函数 调用优先级


1 . 成员函数 优先级高于 扩展函数 : 如果 接收者类型 的扩展函数 与 成员函数有相同的函数签名 ( 即 函数名 , 参数列表个数 , 类型 , 顺序 , 完全相同 ) , 调用该签名的函数时 , 总是调用成员函数 , 扩展函数永远无法调用 ;

2 . 扩展函数 成员函数 优先级 代码示例 :

① 代码示例 : 接收类型 Student 扩展函数的函数签名与成员函数都是 print(num : Int) , 成员函数优先级高于扩展函数 , 因此调用该方法签名的方法时 , 总是调用成员函数 , 扩展函数无法被调用到 ;

open class Student {var name : String = "Tom"var age : Int = 18fun print(num : Int){println("成员函数打印学生信息 : 姓名 : ${this.name}, 年龄 : ${this.age}, 学号 : ${num}")}
}//该扩展函数与成员函数签名相同 , 永远不会被调用到
fun Student.print(num : Int){println("扩展函数打印学生信息 : 姓名 : ${this.name}, 年龄 : ${this.age}, 学号 : ${num}")
}fun main() {var student : Student = Student();//成员函数打印学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 1student.print(1)
}

② 执行结果 :

成员函数打印学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 1

VI . 扩展函数 接收者 空值处理


1 . 空值处理的两种类型 :

① 非空类型 : 这是 Kotlin 的默认类型 , 如 Student 类型是非空类型 , 不能被赋值为 null ;

② 可空类型 : 在类型名称后使用 ? 修饰 , 就是可空类型 , 如 Student? 类型是可空类型 , 该类型可以被赋值成 null ;

2 . 可空接收者类型的扩展函数 :

① 可空类型 : 一般情况下 , 扩展函数的接收者不能为空 , 也可以将接收者类型设置为可空类型 ;

② 扩展函数中判空 : 如果接收者类型可以为空 , 那么尽量在扩展函数中进行判空处理 , 防止出现空值异常 ;

3 . 代码示例 : 接收者类型是 Student? 类型 , 那么相应的变量类型也要是 Student? 类型 ;

open class Student {var name : String = "Tom"var age : Int = 18
}//可空接收者类型的扩展函数
fun Student?.print(num : Int){if(this == null){println("当前学生对象没有实例化")}else {println("扩展函数打印学生信息 : 姓名 : ${this.name}, 年龄 : ${this.age}, 学号 : ${num}")}
}fun main() {/*默认情况下 变量是非空类型的变量 , 不能被赋值成 null如果变量类型后使用 ? 修饰 , 说明变量可以呗设置为空 , 可以呗赋值 null*/var student : Student? = Student()//必须是 Student? 类型的变量才能被赋值成 null//  Student 类型的变量不能被赋值 nullstudent = null//当前学生对象没有实例化student.print(1)
}

执行结果 :

当前学生对象没有实例化

【Kotlin】扩展函数 ( 扩展函数声明 | 调用方式 | 与成员函数优先级 | 接收者空值处理 )相关推荐

  1. const对象不能调用非const成员函数

    在C++中,可以用const来定义一个const对象,但const对象不可以调用类中的非const成员函数 原因 引发原因:: 由调用成员函数时隐式传入的当前对象的this指针引起. 非const成员 ...

  2. 成员函数的选择调用一一常成员函数 (12 分)

    成员函数的选择调用一一常成员函数 (12 分) 类中的常对象选择调用常成员函数.语法要点: 如果将一个对象说明为常对象,则通过该常对象只能调用它的常成员函数, 而不能调用其他成员函数.补充完整复数类的 ...

  3. 函数指针调用类的成员函数

    1 在每个被调用函数之前加上static, 可以使成员函数脱离对象信息单独存在,虽然它属于这个类,但是没有附带上对象信息,但是前提是,static成员函数不能使用对象的信息(成员和函数). 2 使用一 ...

  4. const对象只能调用const成员函数、不能调用非const成员函数;非const对象可以调用const成员函数

    引发原因: 由调用成员函数时隐式传入的当前对象的this指针引起. 1. 非const成员函数中的隐式参数:classA* this 2. const成员函数中的隐式参数:const classA* ...

  5. C++ const对象与非const对象的相互调用、const成员函数与非const成员函数的相互调用

    1)const对象可以调用非const成员函数吗? 答:不能.const修饰的对象实则修饰的是该对象的this指针,并且const修饰的成员不能进行修改,如果使用const调用非const成员函数,可 ...

  6. 同一类的不同对象,在调用相同的成员函数时,入口地址是相同的

    一般成员函数的第一个参数默认是this(可以不写),this指针指向调用这个函数的对象,所以可以给函数传入不同的参数,输出不同的值,而且互不影响. 但是静态成员函数没有this指针. 定义的对象,编译 ...

  7. 为什么不能线程调用类的成员函数_C++多线程编程之创建线程的几种方法

    点蓝色字关注"CurryCoder的程序人生" 微信公众号:CurryCoder的程序人生 怕什么真理无穷,进一寸有一寸的欢喜 1.线程基础知识 可执行程序运行起来,就会生成一个进 ...

  8. C++指向成员函数的指针

    C++指向函数的指针定义方式为: 返回类型 (*指针名)(函数参数列表),例如 void (*p)(int)是指向一个返回值为void 参数为int类型的函数. 而若想定义一个指向类成员函数的函数指针 ...

  9. 【Kotlin】Lambda 表达式 ( 简介 | 表达式语法 | 表达式类型 | 表达式返回值 | 调用方式 | 完整示例 )

    文章目录 I . Lambda 表达式 简介 II . Lambda 表达式语法 III . Lambda 表达式类型 IV . Lambda 表达式返回值 V . Lambda 表达式调用 VI . ...

最新文章

  1. OpenCV+python:霍夫变换与直线检测
  2. WEB学习-CSS盒模型
  3. 如何在C ++中使用数组?
  4. Makefile 使用总结【转】
  5. sql里判断字段是否为空值
  6. 计算机考试报名无法弹出支付界面,教资报名支付页面不弹出怎么办 2021教师资格证报名入口网址...
  7. [转] Java中的容器
  8. redis分布式锁的这些坑,我怀疑你是假的开发
  9. 论文阅读:Uncertainty-aware Joint Salient Object and Camouflaged Object Detection
  10. 设置eclipse中xml的默认编辑器、行数、xsd和dtd
  11. stopwords怎么用_【技术】怎么用Python画出好看的词云图?
  12. 数字图像处理艺术化效果——彩色图像转化为灰度图像(黑白照片)
  13. 【PM杂谈】我理解的项目管理
  14. ECCV 2022开奖!清华、浙大校友斩获最佳论文奖
  15. matlab复数信号_信号之间的时延估计(续)
  16. 显示器分辨率的英文(XGA、SXGA、UXGA、WSXGA等等来表示)
  17. Bioinformatics生物信息专业相关网址
  18. 网络安全——企业渗透一
  19. 冷喷涂服务行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  20. 再造STM32---第二十二部分:CAN—通讯实验

热门文章

  1. sql server 存储过程 SET NOCOUNT ON?
  2. Win2000域控制器+Exchange2000迁移至Win2003域控制器+Exchange2003
  3. OO第一单元总结博客
  4. Mysql优化原则_小表驱动大表IN和EXISTS的合理利用
  5. C primer 第六章循环 习题6.7
  6. 收缩Mysql的ibdata1文件大小方法
  7. [转]Windows Shell 编程 第十一章 【来源:http://blog.csdn.net/wangqiulin123456/article/details/7987992】...
  8. Inserting/Removing shutters and filters
  9. 脚本调用后台代码 asp.net ajax
  10. JRE System Library、Referenced Libraries、Web App Libraries的含义