文章目录
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 : Int this 关键字 : 使用 this 关键字可以在扩展函数中访问对象中的成员 ( 注意可见性 ) */ fun Student.print(num : Int){ println("打印学生信息 : 姓名 : ${this.name}, 年龄 : ${this.age}, 学号 : ${num}") } fun main() { //调用 Student 对象的扩展函数 var student = Student(); //打印学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 1 student.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, 学号 : 1 student.print(1) // 2 . 变量声明为父类类型 , 赋值子类对象 //接收者类型声明为 Student , 但实际对象是 MaleStudent 类型的 // 此时扩展函数调用 Student 接收类型 的扩展函数 var maleStudent : Student = MaleStudent() //打印学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 2 maleStudent.print(2) // 3 . 变量声明为子类类型 , 赋值子类对象 //接收者类型声明为 MaleStudent , 实际对象是 MaleStudent 类型的 // 此时扩展函数调用 MaleStudent 接收类型 的扩展函数 var maleStudent2 : MaleStudent = MaleStudent() //打印男学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 3 maleStudent2.print(3) }
执行结果 :
打印学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 1
打印学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 2
打印男学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 3
1
2
3
V . 扩展函数 调用优先级
1 . 成员函数 优先级高于 扩展函数 : 如果 接收者类型 的扩展函数 与 成员函数有相同的函数签名 ( 即 函数名 , 参数列表个数 , 类型 , 顺序 , 完全相同 ) , 调用该签名的函数时 , 总是调用成员函数 , 扩展函数永远无法调用 ;
2 . 扩展函数 成员函数 优先级 代码示例 :
① 代码示例 : 接收类型 Student 扩展函数的函数签名与成员函数都是 print(num : Int) , 成员函数优先级高于扩展函数 , 因此调用该方法签名的方法时 , 总是调用成员函数 , 扩展函数无法被调用到 ;
open class Student { var name : String = "Tom" var age : Int = 18 fun 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, 学号 : 1 student.print(1) }
② 执行结果 :
成员函数打印学生信息 : 姓名 : Tom, 年龄 : 18, 学号 : 1
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 类型的变量不能被赋值 null student = null //当前学生对象没有实例化 student.print(1) }
执行结果 :
当前学生对象没有实例化