User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   Kotlin   ›   Kotlin Notes   ›   正文
Kotlin Notes

Kotlin-类型初步—扩展方法(八)

2021-01-12 22:46:41
654  0 0
参考目录 隐藏
1) 扩展函数
2) 扩展程序被静态解析
3) 扩展一个空对象
4) 伴生对象的扩展
5) 扩展的作用域
6) 扩展声明为成员

阅读完需:约 6 分钟

扩展函数

Kotlin与C#和Go类似,提供了扩展一个新功能的类,而不必继承类或使用任何类型的设计模式。

这是通过称为扩展名的特殊声明完成的。 Kotlin支持扩展功能和扩展属性。

您需要在String类中使用一种方法,该方法返回删除了第一个和最后一个字符的新字符串。此方法在String类中不存在。您可以使用扩展函数来完成此任务。

fun String.removeFirstLastChar(): String =  this.substring(1, this.length - 1)

fun main(args: Array<String>) {
    val myString= "Hello Everyone"
    val result = myString.removeFirstLastChar()
    println("输出结果: $result")
}

运行该程序时,输出为:

输出结果: ello Everyon

在这里,扩展函数removeFirstLastChar ()被添加到String类中。

类名是接收者类型(在我们的示例中为String类)。 扩展函数中的this关键字引用接收者对象。


扩展程序被静态解析

扩展不会实际修改它们扩展的类。 通过定义扩展名,不将新成员插入到类中,而只能使用这种类型的变量上的点符号来调用新的函数。

扩展功能是静态调度的,即它们不是接收器类型的虚拟机。 这意味着被调用的扩展函数由调用该函数的表达式的类型决定,而不是在运行时评估该表达式的结果的类型。 例如:

open class C

class D: C()

fun C.foo() = "c"   // 扩展函数 foo

fun D.foo() = "d"   // 扩展函数 foo

fun printFoo(c: C) {
    println(c.foo())  // 类型是 C 类
}

fun main(arg:Array<String>){
    printFoo(D())
}

编译运行以上 Kotlin 范例,输出结果如下

c

若扩展函数和成员函数一致,则使用该函数时,会优先使用成员函数。

class C {
    fun foo() { println("成员函数") }
}

fun C.foo() { println("扩展函数") }

fun main(arg:Array<String>)
{
    var c = C()
    c.foo()
}

输出结果如下

成员函数

扩展一个空对象

在扩展函数内, 可以通过 this 来判断接收者是否为 null

这样,即使接收者为 null,也可以调用扩展函数

fun Any?.toString(): String
{
    if (this == null) return "null"
    // 空检测之后,“this”会自动转换为非空类型,所以下面的 toString()
    // 解析为 Any 类的成员函数
    return toString()
}

fun main(arg:Array<String>)
{
    var t = null
    println(t.toString())
}

编译运行以上 Kotlin 范例,输出结果如下

null

扩展属性除了函数,Kotlin 也支持属性对属性进行扩展

val <T> List<T>.lastIndex: Int
    get() = size - 1

扩展属性允许定义在类或者包内,不允许定义在函数中

初始化属性因为属性没有后端字段(backing field),所以不允许被初始化,只能由显式提供的 getter/setter 定义。

val Foo.bar = 1 // 错误:扩展属性不能有初始化器

扩展属性只能被声明为 val


伴生对象的扩展

如果一个类定义有一个伴生对象 ,Kotlin 允许为伴生对象定义扩展函数和属性

伴生对象通过 类名. 形式调用伴生对象,伴生对象声明的扩展函数,通过用类名限定符来调用

class MyClass
{
    companion object { }  // 将被称为 "Companion"
}

fun MyClass.Companion.foo()
{
    println("伴随对象的扩展函数")
}

val MyClass.Companion.no: Int
    get() = 10

fun main(args: Array<String>)
{
    println("no:${MyClass.no}")
    MyClass.foo()
}

编译运行以上 Kotlin 范例,输出结果如下

no:10
伴随对象的扩展函数

扩展的作用域

通常扩展函数或属性定义在顶级包下

package foo.bar

fun Baz.goo() { …… }

要使用所定义包之外的一个扩展, 通过 import 导入扩展的函数名进行使用

package com.example.usage

import foo.bar.goo // 导入所有名为 goo 的扩展
                   // 或者
import foo.bar.*   // 从 foo.bar 导入一切

fun usage(baz: Baz) {
    baz.goo()
}

扩展声明为成员

Kotlin 允许在一个类内部为另一个类声明扩展方法

在这样的扩展中,有个多个隐含的接受者,其中扩展方法定义所在类的实例称为分发接受者

而扩展方法的目标类型的实例称为扩展接受者

class D 
{
    fun bar() { println("D bar") }
}

class C 
{
    fun baz() { println("C baz") }

    fun D.foo() {
        bar()   // 调用 D.bar
        baz()   // 调用 C.baz
    }

    fun caller(d: D) {
        d.foo()   // 调用扩展函数
    }
}

fun main(args: Array<String>)
{
    val c: C = C()
    val d: D = D()
    c.caller(d)

}

编译运行以上 Kotlin 范例,输出结果如下

D bar
C baz

在 C 类内,创建了 D 类的扩展。此时,C 被成为分发接受者,而 D 为扩展接受者

从上例中可以看到,在扩展函数中,可以调用派发接收者的成员函数

假如在调用某一个函数,而该函数在分发接受者和扩展接受者均存在,则以扩展接收者优先,要引用分发接收者的成员你可以使用限定的 this 语法

class D
{
    fun bar() { println("D bar") }
}

class C
{
    fun bar() { println("C bar") }  // 与 D 类 的 bar 同名

    fun D.foo() {
        bar()         // 调用 D.bar(),扩展接收者优先
        this@C.bar()  // 调用 C.bar()
    }

    fun caller(d: D) {
        d.foo()   // 调用扩展函数
    }
}

fun main(args: Array<String>) {
    val c: C = C()
    val d: D = D()
    c.caller(d)

}

编译运行以上 Kotlin 范例,输出结果如下

D bar
C bar

以成员的形式定义的扩展函数, 可以声明为 open , 而且可以在子类中覆盖

也就是说, 在这类扩展函数的派发过程中, 针对分发接受者是虚拟的(virtual), 但针对扩展接受者仍然是静态的

open class D 
{
}

class D1 : D() 
{
}

open class C 
{
    open fun D.foo() {
        println("D.foo in C")
    }

    open fun D1.foo() {
        println("D1.foo in C")
    }

    fun caller(d: D) {
        d.foo()   // 调用扩展函数
    }
}

class C1 : C()
{
    override fun D.foo() {
        println("D.foo in C1")
    }

    override fun D1.foo() {
        println("D1.foo in C1")
    }
}


fun main(args: Array<String>)
{
    C().caller(D())   // 输出 "D.foo in C"
    C1().caller(D())  // 输出 "D.foo in C1" —— 分发接收者虚拟解析
    C().caller(D1())  // 输出 "D.foo in C" —— 扩展接收者静态解析

}

编译运行以上 Kotlin 范例,输出结果如下

D.foo in C
D.foo in C1
D.foo in C

如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

0 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 594044浏览

随机文章
SpringBoot—通过CORS解决跨域问题
5年前
Docker—网络(六)
5年前
Java—根据经纬度计算实际距离
5年前
Java—并发编程(六)JUC锁 – (12) Phaser
4年前
Java—并发编程(六)JUC锁 – (8) CountDownLatch
4年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 594044 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付