Kotlin 能够对一个类或接口扩展新功能而无需继承该类或者使用像装饰者 这样的设计模式。 这通过叫做扩展的特殊声明完成。
说人话就是,在不继承或修改原类的前提下,给已有类增加新功能的方法
1.Kotlin 扩展函数
markdown
扩展函数写法:
fun 扩展者类型.函数名(参数列表): 返回类型 {
// 函数体
}
- **扩展者类型**:你要扩展的类,比如 `String`、`Int`、`View` 等。
- **函数名**:扩展的方法名。
- **参数列表**:正常函数参数。
- **返回类型**:可以有返回值,也可以是 `Unit`。
扩展函数是 Kotlin 的一个核心特性,可以给已有类"额外添加方法",而不需要继承或修改原类
1.1:扩展函数特点
-
无需继承
不用创建子类或修改源代码,就可以给类增加方法。
-
调用方式和普通方法一样
看起来像是这个类本身的方法,但底层其实是静态函数调用。
-
不能访问类的私有成员
扩展函数只能调用类的公有 API。
1.2:扩展函数生效和调用顺序
Kotlin 的 扩展函数 从语法上看像是类的方法,但底层实现其实是 静态方法 ,并不是修改了类本身。它是通过 编译器在调用时做"静态分发" 来实现的。
编译器静态分发
:
大白话理解,编译器在编译apk时将 扩展方法编译成一个静态方法,且将调用对象最为参数传入这个静态方法,调用的时候直接执行.
-
编译器在编译时把扩展函数 转换为静态方法
-
第一个参数就是扩展函数的 接收者对象(this)
-
调用的时候直接调用这个静态方法 → 实现了"静态分发"
kotlin
1: 创建扩展函数
ExtendUtil.kt
fun String.safeAppend(content: String): String = this + content
2:编译后扩展函数会变为静态方法 (会将对象当参数传进去)
//自动生成的类,名称基于文件名 + "Kt"
ExtendUtilKT{
// 扩展函数被转换为静态方法
// 第一个参数是接收者对象(原 String 实例)
public static final String safeAppend(String $this, String content) {
// 原 Kotlin 中的 "this + content" 被转换为对参数的操作
return $this + content;
}
3. 编译时会将 调用方法也转换一下
"测试".safeAppend("1")
编译后会变为
String result = ExtendUtilKT.safeAppend("测试", "1");
所以会认为是对象直接调用其实不是 对象只是作为参数传递进去的
1.3 扩展函数示例
kotlin
fun View.show() {
this.visibility = View.VISIBLE
}
fun View.hide() {
this.visibility = View.GONE
}
// 使用
button.show()
textView.hide()
2.扩展属性
Kotlin 的扩展属性(Extension Properties)是另一种扩展特性,允许你为已有的类添加新的属性,而无需修改类的源代码。与扩展函数类似,它也是一种编译期的语法糖,不会真正改变目标类的结构。
css
// 定义扩展属性 val/var 类名.属性名: 类型 get() = // getter 逻辑 // 扩展属性不能有初始化器,也不能有幕后字段(backing field)
关键特点
- 没有幕后字段 :扩展属性不能像普通属性那样拥有
field
关键字对应的幕后字段,因此必须显式提供 getter(对于var
还需要 setter)。 - 本质是函数 :扩展属性在编译后会被转换为一对
getter/setter
静态方法(类似扩展函数)。 - 不能初始化 :由于没有幕后字段,无法在定义时赋值(如
val String.len = 10
是错误的)。
markdown
### 关键特点
1. **没有幕后字段**:扩展属性不能像普通属性那样拥有 `field` 关键字对应的幕后字段,因此必须显式提供 getter(对于 `var` 还需要 setter)。
1. **本质是函数**:扩展属性在编译后会被转换为一对 `getter/setter` 静态方法(类似扩展函数)。
1. **不能初始化**:由于没有幕后字段,无法在定义时赋值(如 `val String.len = 10` 是错误的)。
注意事项
-
扩展属性不能访问目标类的私有 / 受保护成员,只能使用公开 API。
-
对于
var
类型的扩展属性,setter 通常只能用于有状态的对象(如自定义类),对于不可变类(如String
、Int
),setter 无法真正修改对象状态。 -
扩展属性的调用同样依赖编译期转换,运行时性能与普通静态方法调用一致。
扩展属性是对扩展函数的补充,它让代码在保持简洁的同时,拥有更接近原生属性的调用体验。
3.扩展函数的示例
kotlin
// 为 String 类添加扩展方法
fun String.isEmail(): Boolean {
val emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$".toRegex()
return matches(emailRegex)
}
fun String.toTitleCase(): String {
return split(" ").joinToString(" ") {
it.lowercase().replaceFirstChar { char -> char.uppercase() }
}
}
// 为 String 类添加扩展属性
val String.wordCount: Int
get() = if (isBlank()) 0 else split("\\s+".toRegex()).size
val String.firstWord: String?
get() = split("\\s+".toRegex()).firstOrNull()
// 为 List<Int> 类添加扩展方法
fun List<Int>.sumOfEvenNumbers(): Int {
return filter { it % 2 == 0 }.sum()
}
fun List<Int>.averageOrZero(): Double {
return if (isEmpty()) 0.0 else average()
}
// 为 List<Int> 类添加扩展属性
val List<Int>.maxOrNull: Int?
get() = if (isEmpty()) null else max()
val List<Int>.hasNegativeNumbers: Boolean
get() = any { it < 0 }
fun main() {
// 测试 String 扩展
val text = "hello world! this is a test"
val email = "test@example.com"
println("Text in title case: ${text.toTitleCase()}") // 扩展方法
println("Is valid email: ${email.isEmail()}") // 扩展方法
println("Word count: ${text.wordCount}") // 扩展属性
println("First word: ${text.firstWord}") // 扩展属性
// 测试 List<Int> 扩展
val numbers = listOf(1, 2, 3, 4, 5, 6, -1)
println("\nSum of even numbers: ${numbers.sumOfEvenNumbers()}") // 扩展方法
println("Average (or zero): ${numbers.averageOrZero()}") // 扩展方法
println("Maximum value: ${numbers.maxOrNull}") // 扩展属性
println("Has negative numbers: ${numbers.hasNegativeNumbers}") // 扩展属性
}
总结:扩展特性的价值
-
简化代码:无需继承 / 装饰者模式,就能扩展第三方库或系统类,避免类结构冗余。
-
提升可读性 :调用方式与原生成员一致,代码更直观(如
view.show()
比ViewUtil.show(view)
更简洁)。 -
无性能损耗:编译期完成转换,运行时仅执行静态方法,性能与原生代码持平。
扩展特性是 Kotlin 提升开发效率的核心手段之一,广泛用于日常开发(如 Android 中 View
的显示控制、String
的格式处理等)。