【Kotlin】扩展函数作用域分析 ( 扩展函数导入 | 扩展函数重载 | 扩展函数作用域优先级 )



I . 扩展函数 作用域 总结



扩展函数作用域总结 :


① 扩展函数作用域 : 扩展函数使用需要导入包 , 如果在本包中使用 , 可以默认不导入包 ;

② 扩展函数可以重载 : 函数名相同 , 函数签名不同的扩展函数可以同时定义 , 导入包时导入一次即可调用所有的重载的扩展函数 ;

③ 扩展函数作用域优先级 : 声明导入的扩展函数优先级高于默认包的优先级 , 声明导入哪个包就调用哪个包的扩展函数 ;



II . 扩展函数 作用域



1 . 扩展函数作用域 : 定义一个扩展函数 , 默认只能在本包中调用 , 如果在别的包调用扩展函数 , 需要导入扩展函数 ;


2 . 扩展函数导入 : 调用接收者类型的扩展函数 , 需要导入扩展函数的包 , 导入格式为 :

import 包名.扩展函数名

3 . 调用定义在本包里的扩展函数 : 可以直接调用 , 导入扩展函数的操作可以省略 , 写上也不会出错 ;


4 . 调用定义在其它包的扩展函数 : 必须导入扩展函数 , 才能调用该扩展函数 ;



III . 扩展函数 作用域 简单调用示例



1 . 分别在 本包 和 外包 中定义扩展函数 :


① 本包定义扩展函数 : 普通的扩展函数定义 , 在 extendbean 包的文件下定义 Student 类 , 在 extendbean 包的文件下定义 Student 类的扩展函数 ;

package extendbean

class Student {
    var name : String = "Tom"
    var age : Int = 18
}

//在同一个文件中扩展
fun Student.printName(){
    println("${this.name}")
}

② 外包定义扩展函数 : 外包中定义 Student 类的扩展函数 , 自然需要导入 Student 类 ;

package extenddeclare

import extendbean.Student

//定义扩展函数
fun Student.printNameAndAge(){
    println("${this.name} , ${this.age}")
}


2 . 本包 中调用扩展函数 :


① 代码分析 : 在 extendbean 包中调用 extenddeclare 包中的为 Student 扩展的 printNameAndAge 函数 , 需要使用 import extenddeclare.printNameAndAge 导入该扩展函数 ;

package extendbean

//本包中可以不同导入 Student 包
//import extendbean.Student

//在本包内定义的扩展函数就不需要导入包了
//import extendbean.printAge
//import extendbean.printName

//使用 Student 的扩展 , 也需要导入 扩展函数所在包名.扩展函数名
import extenddeclare.printNameAndAge

fun main() {
    var student : Student = Student()
    student.printNameAndAge()
    student.printName()
}

② 执行结果 :

Tom , 18
Tom


3 . 外包 中调用扩展函数 :


① 代码分析 : 在 extendusage 包中调用 extendbean 包中的 Student 类 和 扩展函数 , 以及 extenddeclare 包中定义的 printNameAndAge 扩展函数 , 需要将 Student 类以及所有的扩展函数都声明导入 , 才可以使用 ;

package extendusage

//使用到 Student 需要导入该类的包
import extendbean.Student

//使用 Student 的扩展 , 也需要导入 扩展函数所在包名.扩展函数名
import extendbean.printName
import extenddeclare.printNameAndAge

fun main() {
    var student : Student = Student()
    student.printNameAndAge()
    student.printName()
}

② 执行结果 :

Tom , 18
Tom


IV . 扩展函数 重载分析



1 . 包内禁止定义相同函数签名的扩展函数 : 在同一个包里 , 定义了一个扩展函数后 , 不允许定义相同函数签名的扩展函数 ; 不管是定义在同一个文件中 , 还是不同的文件中 , 函数签名不可以重复 ;

在这里插入图片描述


2 . 原理分析 : 因为扩展函数是根据 包名.扩展函数名 识别的 , 如果在同一个包内定义了相同函数签名的扩展函数 , 无法识别应该调用哪个扩展函数 ;


3 . 重载说明 : 扩展函数在同一个包内 , 可以进行重载操作 , 即定义函数名相同 , 参数列表和返回值类型或顺序不同的函数 , 两个同名函数签名不同 , 因此可以区分调用 ;

在这里插入图片描述



V . 扩展函数 重载代码示例



1 . 重载扩展函数导入 : 对于重载的扩展函数 , 可以导入一次包即可通过函数签名调用不同的扩展函数 ;


2 . 定义重载扩展函数 : 为 Student 扩展了两个函数 , 分别是 printName() 和 printName(num : Int) , 这两个函数签名不同 , 可以定义 , 调用时根据不同的函数签名分别调用 ;

package extendbean

class Student {
    var name : String = "Tom"
    var age : Int = 18
}

//在同一个文件中扩展
fun Student.printName(){
    println("${this.name}")
}

//测试重载的函数可以只声明一次
fun Student.printName(num : Int){
    println("${this.name}")
}

3 . 调用重载扩展函数 : 根据不同的函数签名调用不同的扩展函数 ;

package extendbean

fun main() {
    var student : Student = Student()
    student.printName()
    student.printName(10)
}

4 . 执行结果 :

Tom
name : Tom , num : 10


VI . 扩展函数 作用域 优先级 分析



本节讨论的是在不同包定义的相同函数签名的扩展函数调用问题


1 . 不同的包可以定义相同函数签名的扩展函数 : 在不同的包内 , 可以定义相同函数签名的扩展函数 , 调用时需要考虑各种情况 ; 其导入包的扩展函数优先级较高 , 没有发现导入包 , 才会去默认的本包中查找是否有定义该签名的扩展函数 ;


2 . 情况 一 : 在包内调用本包和外包的 相同签名的 扩展函数 ;

① 导入的包优先级高 : 如果导入外包扩展函数 , 就会调用外包的扩展函数 ;

② 本包默认优先级较低 : 如果没有导入 , 就会默认调用本包定义的的扩展函数 ;


3 . 情况 二 : 在一个包中调用 其它两个包 的 相同签名的 扩展函数 ;

① 调用优先级 : 导入哪个包 , 就调用哪个包的扩展函数 ;

② 重复导入 : 两个包都导入会报错 ;

在这里插入图片描述



VII . 扩展函数 作用域 优先级 代码示例分析



1 . 不同包中定义相同函数签名的扩展函数 : 为 Student 类在不同的包中定义相同函数签名的扩展函数 ;


① 在 extendbean 包定义了 Student.printNameAndAge() 扩展函数 :

package extendbean

class Student {
    var name : String = "Tom"
    var age : Int = 18
}

//定义扩展函数
fun Student.printNameAndAge(){
    println("${this.name} , ${this.age}")
}

② 在 extenddeclare 包也定义了相同函数签名的 Student.printNameAndAge() 扩展函数 :

package extenddeclare

import extendbean.Student

//定义扩展函数
fun Student.printNameAndAge(){
    println("${this.name} , ${this.age}")
}


2 . 在 extendbean 包中调用扩展函数分析 :


① 没有导入 extenddeclare.printNameAndAge 包 : 直接根据函数签名调用扩展函数 , 此时调用的是本包中定义的扩展函数 ;

package extendbean

//使用 Student 的扩展 , 也需要导入 扩展函数所在包名.扩展函数名
//import extenddeclare.printNameAndAge

//此处注释掉了导入包的操作

fun main() {
    var student : Student = Student()
    student.printNameAndAge()
}

执行结果 : 根据结果可以看到 , 调用的是 extendbean 包中的扩展函数 ;

extendbean : Tom , 18

② 导入了 extenddeclare.printNameAndAge 包 :

package extendbean

//使用 Student 的扩展 , 也需要导入 扩展函数所在包名.扩展函数名
import extenddeclare.printNameAndAge

fun main() {
    var student : Student = Student()
    student.printNameAndAge()
}

执行结果 : 根据结果可以看到 , 调用的是 extenddeclare 包中的扩展函数 ;

extenddeclare : Tom , 18


2 . 在 extendusage 包中调用扩展函数分析 : 这是个第三方包 , 分别在 extendbean 和 extenddeclare 定义了两个相同函数签名的 Student 扩展函数 ;


① 声明哪个包就调用对应包的方法 : 此时声明导入的是 extendbean.printNameAndAge , 就会调用 extendbean 包下的扩展函数 ;

package extendusage

//使用到 Student 需要导入该类的包
import extendbean.Student

import extendbean.printNameAndAge
//import extenddeclare.printNameAndAge

fun main() {
    var student : Student = Student()
    student.printNameAndAge()
}

执行结果 :

extendbean : Tom , 18

② 如果都声明报错 : 如果两个包都声明 , 会如下错误 Overload resolution ambiguity. All these functions match. ;

在这里插入图片描述

发布了329 篇原创文章 · 获赞 1057 · 访问量 172万+

猜你喜欢

转载自blog.csdn.net/han1202012/article/details/105263661
今日推荐