2-2-15 快速掌握Kotlin-超类定义扩展函数

34 阅读4分钟

Kotlin 中为超类定义扩展函数

在 Kotlin 中,您可以在超类(如 AnyAny?Number 等)上定义扩展函数,这样所有继承该类的子类都能使用这些扩展。

1. Any 类定义扩展函数

Any 是 Kotlin 中所有非空类型的根类,为它定义扩展函数意味着几乎所有对象都能使用:

// 为 Any 类定义扩展函数 - 所有非空对象都能使用
fun Any?.safeToString(): String {
    return this?.toString() ?: "null"
}

fun Any.printType() {
    println("对象类型: ${this::class.simpleName}")
    println("对象哈希码: ${this.hashCode()}")
}

// 使用
val str: String? = null
println(str.safeToString())  // 输出: null

val number = 42
number.printType()  // 输出: 对象类型: Int

val list = listOf(1, 2, 3)
list.printType()  // 输出: 对象类型: ArrayList

2. Any? 类定义扩展函数

Any? 是所有可空和非空类型的根类:

// 为 Any? 定义扩展函数 - 包括可空类型
fun Any?.isNotNullAnd(condition: (Any) -> Boolean): Boolean {
    return this != null && condition(this)
}

fun Any?.ifNotNull(block: (Any) -> Unit) {
    if (this != null) block(this)
}

// 使用
val value: Any? = "Hello"
val result = value.isNotNullAnd { it is String }  // true

value.ifNotNull {
    println("值存在: $it")
}

3. Number 超类定义扩展函数

Number 是所有数值类型的超类(Int、Double、Float 等):

// 为 Number 定义扩展函数 - 所有数值类型都能使用
fun Number.toFormattedString(): String {
    return when (this) {
        is Int -> "整数: $this"
        is Double -> "双精度: ${"%.2f".format(this)}"
        is Float -> "浮点数: ${"%.1f".format(this)}"
        else -> this.toString()
    }
}

fun Number.square(): Number {
    return when (this) {
        is Int -> this * this
        is Double -> this * this
        is Float -> this * this
        else -> throw UnsupportedOperationException("不支持的数值类型")
    }
}

// 使用
val intValue: Number = 5
println(intValue.toFormattedString())  // 输出: 整数: 5
println(intValue.square())  // 输出: 25

val doubleValue: Number = 3.1415
println(doubleValue.toFormattedString())  // 输出: 双精度: 3.14

4. CharSequence 超类定义扩展函数

CharSequenceStringStringBuilderCharBuffer 等的超类:

// 为 CharSequence 定义扩展函数 - String、StringBuilder 等都能使用
fun CharSequence.containsIgnoreCase(other: CharSequence): Boolean {
    return this.toString().contains(other.toString(), ignoreCase = true)
}

fun CharSequence.countWords(): Int {
    return this.split("\\s+".toRegex()).count { it.isNotBlank() }
}

fun CharSequence.truncate(maxLength: Int): CharSequence {
    return if (this.length <= maxLength) this
    else this.subSequence(0, maxLength - 3) + "..."
}

// 使用
val string: CharSequence = "Hello World"
val builder: CharSequence = StringBuilder("Kotlin Programming")

println(string.containsIgnoreCase("WORLD"))  // true
println(builder.countWords())  // 2
println(string.truncate(8))  // Hello...

5. Comparable 超类定义扩展函数

// 为 Comparable 定义扩展函数
fun <T : Comparable<T>> T.isBetween(min: T, max: T): Boolean {
    return this in min..max
}

fun <T : Comparable<T>> T.clamp(min: T, max: T): T {
    return when {
        this < min -> min
        this > max -> max
        else -> this
    }
}

// 使用
val number = 15
println(number.isBetween(10, 20))  // true
println(25.clamp(0, 100))  // 25
println(150.clamp(0, 100))  // 100

6. Collection 超类定义扩展函数

// 为 Collection 定义扩展函数
fun <T> Collection<T>.secondOrNull(): T? {
    return this.elementAtOrNull(1)
}

fun <T> Collection<T>.isNotEmptyAnd(predicate: (Collection<T>) -> Boolean): Boolean {
    return this.isNotEmpty() && predicate(this)
}

// 使用
val list = listOf(1, 2, 3, 4)
val set = setOf("A", "B", "C")

println(list.secondOrNull())  // 2
println(set.isNotEmptyAnd { it.size > 2 })  // true

7. 为自定义超类定义扩展函数

// 定义自定义超类
open class Shape(val name: String)

class Circle(name: String, val radius: Double) : Shape(name)
class Rectangle(name: String, val width: Double, val height: Double) : Shape(name)

// 为 Shape 超类定义扩展函数
fun Shape.getDescription(): String {
    return "形状: $name"
}

// 这个扩展函数所有 Shape 的子类都能使用
fun Shape.printInfo() {
    println(this.getDescription())
    when (this) {
        is Circle -> println("半径: $radius")
        is Rectangle -> println("宽度: $width, 高度: $height")
        else -> println("未知形状")
    }
}

// 使用
val circle = Circle("圆形", 5.0)
val rectangle = Rectangle("矩形", 4.0, 6.0)

circle.printInfo()
// 输出:
// 形状: 圆形
// 半径: 5.0

rectangle.printInfo()
// 输出:
// 形状: 矩形
// 宽度: 4.0, 高度: 6.0

8. 使用类型参数约束定义超类扩展函数

// 使用上界约束定义泛型扩展函数
fun <T : Any> T?.orDefault(default: T): T {
    return this ?: default
}

fun <T : CharSequence> T.ensurePrefix(prefix: String): T {
    return if (this.startsWith(prefix)) this
    else "$prefix$this" as T
}

// 使用
val nullableString: String? = null
println(nullableString.orDefault("默认值"))  // 输出: 默认值

val path = "file.txt"
println(path.ensurePrefix("/"))  // 输出: /file.txt

9. 实际项目应用示例

Android 开发中的应用

// 为 View 超类定义扩展
fun View.setVisible(isVisible: Boolean) {
    this.visibility = if (isVisible) View.VISIBLE else View.GONE
}

fun View.setOnSingleClickListener(delay: Long = 500, onClick: (View) -> Unit) {
    var lastClickTime = 0L
    this.setOnClickListener {
        val currentTime = System.currentTimeMillis()
        if (currentTime - lastClickTime > delay) {
            lastClickTime = currentTime
            onClick(it)
        }
    }
}

// 使用 - 所有 View 子类都能使用
button.setVisible(true)
imageView.setOnSingleClickListener {
    // 防止重复点击
}

响应式编程中的应用

// 为 Flow 超类定义扩展
fun <T> Flow<T>.throttleFirst(windowDuration: Long): Flow<T> = flow {
    var lastEmissionTime = 0L
    collect { value ->
        val currentTime = System.currentTimeMillis()
        if (currentTime - lastEmissionTime > windowDuration) {
            lastEmissionTime = currentTime
            emit(value)
        }
    }
}

fun <T> Flow<T>.debug(tag: String): Flow<T> = flow {
    collect { value ->
        println("[$tag] 接收到: $value")
        emit(value)
    }
}

10. 注意事项和最佳实践

注意事项

// 1. 扩展函数不会被子类重写
open class Animal
class Dog : Animal()

fun Animal.speak() = "Animal sound"
fun Dog.speak() = "Woof!"

fun main() {
    val animal: Animal = Dog()
    println(animal.speak())  // 输出: Animal sound (不是 Woof!)
}

// 2. 避免与现有成员函数冲突
// 如果扩展函数与成员函数签名相同,成员函数优先
class MyClass {
    fun doSomething() = println("成员函数")
}

fun MyClass.doSomething() = println("扩展函数")  // 不会被调用

// 3. 谨慎使用 Any 扩展
fun Any.customToString(): String {
    return "自定义: ${this::class.simpleName}"
}
// 这会影响到所有对象,可能会造成混淆

最佳实践

// 1. 使用特定类型代替 Any,如果可能的话
// 不好:
fun Any?.safeToString(): String = this?.toString() ?: "null"

// 好:
fun CharSequence?.safeToString(): String = this?.toString() ?: ""

// 2. 为扩展函数提供清晰的命名空间
package com.example.extensions.any

fun Any?.debug(): String {
    return "[${this?.javaClass?.simpleName}] $this"
}

// 3. 提供有用的默认值
fun Number?.orZero(): Number {
    return this ?: 0
}

// 4. 考虑性能影响
// 避免在频繁调用的扩展函数中创建过多临时对象

11. 使用 reified 结合超类扩展

// 结合 reified 和超类扩展
inline fun <reified T : Any> Any?.castOrNull(): T? {
    return this as? T
}

inline fun <reified T : Any> Any?.requireType(): T {
    return this as T
}

// 使用
val anyValue: Any = "Hello, World"
val string: String? = anyValue.castOrNull()  // 安全转换
val requiredString: String = anyValue.requireType()  // 不安全转换,失败时抛异常

12. 扩展函数组合使用

// 创建工具函数链
fun Any?.ifNotNullThen(block: (Any) -> Unit): Any? {
    this?.let(block)
    return this
}

fun Any?.ifNullThen(block: () -> Unit): Any? {
    if (this == null) block()
    return this
}

// 使用 - 创建流畅的 API
val result = someNullableValue
    .ifNotNullThen { println("值存在: $it") }
    .ifNullThen { println("值为空") }

总结

为超类定义扩展函数是 Kotlin 中非常强大的特性,它允许您:

  1. 提供通用功能:为所有对象类型添加常用功能
  2. 减少重复代码:避免为每个子类重复定义相同功能
  3. 创建流畅 API:通过扩展函数链提供更好的开发体验
  4. 增强类型安全:通过泛型约束提供类型安全的扩展

但是需要注意:

  • 扩展函数是静态解析的,不支持多态
  • 优先考虑特定类型而非 Any
  • 避免与现有成员函数冲突
  • 合理组织扩展函数的包结构

合理使用超类扩展函数可以显著提高代码的可读性和可维护性。