Kotlin高级特性

1 扩展

扩展函数允许为现有类添加新的方法,而无需修改其源代码。

1.1 扩展函数

// 定义扩展函数
fun String.isUpperCase(): Boolean {
    return this == this.uppercase()
}

// 使用扩展函数
fun main() {
    println("HELLO".isUpperCase())  // 输出: true
}

1.2 扩展属性

// 定义扩展属性
val String.firstLetter: Char
    get() = this[0]

// 使用扩展属性
fun main() {
    println("HELLO".firstLetter)  // 输出: H
}

2 委托

委托是 Kotlin 中实现“组合优于继承”的重要特性。

2.1 属性委托

属性委托允许将属性的逻辑委托给另一个对象,从而实现更灵活的属性管理。属性委托的核心是通过 getValuesetValue 方法控制属性的读取和写入。和重写set get 不同的是它是可以独立作为一个模块,适合一些共用委托逻辑的处理。

应用场景:将通用逻辑(如数据验证、日志记录)抽离出来,实现复用。

2.1.1 自定义委托
// 实现一个正数验证逻辑的委托
class PositiveNumberDelegate {
    private var value: Int = 0

    operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
        return value
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
        if (value < 0) {
            throw IllegalArgumentException("不是正数")
        }
        this.value = value
    }
}

class User {
    // age属性委托给PositiveNumberDelegate
    var age: Int by PositiveNumberDelegate()
}

fun main() {
    val user = User()
    user.age = 25  // 成功
    println("Age: ${user.age}")  // 输出: Age: 25

    try {
        user.age = -1  // 抛出异常
    } catch (e: IllegalArgumentException) {
        println(e.message)  // 输出: 不是正数
    }
}
2.1.2内置委托
lazy

延迟初始化属性,仅在首次访问时初始化,节省资源。

特点

  1. 线程安全:支持 SYNCHRONIZEDVOLATILENONE 三种线程安全模式。
  2. 适用于 val:可用于可空不可变属性,属性类型可以为空,但是必须是val修饰的不可变变量。
// 延时初始化resource
val resource: Resource by lazy { Resource() }
map
val map = mapOf("name" to "John Doe", "age" to 25)
val name: String by map
val age: Int by map
println("name: ${name}")  // 输出: name: John Doe
println("age: ${age}")  // 输出: age: 25
Delegates.observable

观察属性的变化,适用于需要在属性值变化时执行附加操作的场景。

class User {
    var name: String by Delegates.observable("初始值") { prop, old, new ->
        println("${prop.name}$old变为$new")
    }
}

fun main() {
    val user = User()
    user.name = "Alice"  // 输出: name从初始值变为Alice
    user.name = "Bob"    // 输出: name从Alice变为Bob
}
Delegates.vetoable

在属性值变化前进行拦截,适用于需要验证属性值的场景。

class User {
    var age: Int by Delegates.vetoable(0) { prop, old, new ->
        new >= 0  // 验证逻辑
    }
}

fun main() {
    val user = User()
    user.age = 25  // 成功
    try {
        user.age = -1  // 抛出异常
    } catch (e: IllegalArgumentException) {
        println("Invalid age: ${e.message}")
    }
}

2.2 接口委托

将接口的实现委托给另一个对象,从而实现“组合优于继承”的设计原则。这种方式特别适合将通用逻辑抽离出来,实现复用。

interface Logger {
    fun log(message: String)
}

class ConsoleLogger : Logger {
    override fun log(message: String) {
        println("LOG: $message")
    }
}

// 通过接口委托,User有了Logger的功能
class User : Logger by ConsoleLogger() {
    init {
        // 可以直接调用日志打印方法
        log("init")
    }
}

3 自定义运算符

Kotlin 允许通过 operator 关键字重载运算符。

示例

data class Point(val x: Int, val y: Int) {
    operator fun plus(other: Point): Point {
        return Point(x + other.x, y + other.y)
    }
}

fun main() {
    val p1 = Point(1, 2)
    val p2 = Point(3, 4)
    val result = p1 + p2
    println(result)  // 输出: Point(x=4, y=6)
}

支持的运算符

  • 加法(+):plus
  • 减法(-):minus
  • 乘法(*):times
  • 除法(/):div
  • 模运算(%):mod
  • 等等…

4 中缀表达式

Kotlin 允许通过 infix 关键字定义中缀函数,使代码更简洁。

4.1 定义和使用

infix fun String.add(str: String): String {
    return this + str
}

fun main() {
    println("Hello" add "World")  // 输出: HelloWorld
}

4.2 特性

  1. 中缀函数必须是成员函数或扩展函数。
  2. 参数必须只有一个。
  3. 中缀函数的调用方式类似于操作符,但实际上是函数调用。

5 内联函数

内联函数通过 inline 关键字声明,将函数体直接插入到调用点,从而避免函数调用的开销。

5.1定义和使用

// 和reified合用可以获取泛型类型
inline fun <reified T> getType(): String {
    return T::class.qualifiedName ?: "Unknown"
}

5.2 特性

  1. noinline 关键字:显式禁止某个参数被内联。

    inline fun <T> myFunction(a: () -> T, noinline b: () -> T) {
        println(a())  // a 被内联
        println(b())  // b 不被内联
    }
    
  2. 内联函数的限制

    • 内联函数不能包含非内联的高阶函数调用。
    • 内联函数不能包含 return 到外部函数的语句。
    • 内联函数不能被 override

6 内部类

内部类通过 inner 关键字修饰,可以访问外部类的成员。

6.1 定义和使用

class Outer {
    val outerProperty = "Outer Property"

    inner class Inner {
        fun showOuterProperty() {
            println(outerProperty)  // 访问外部类的成员
        }
    }
}

fun main() {
    val inner = Outer().Inner()
    inner.showOuterProperty()  // 输出: Outer Property
}

6.2 匿名内部类

用于实现接口或继承类。

val runnable = object : Runnable {
    override fun run() {
        println("Running...")
    }
}

7 作用域函数

7.1 apply

特点

  • 行为:对对象执行一系列操作,并返回该对象。
  • 返回值:原始对象。
  • 上下文:使用 this 作为上下文参数。
val person = Person("Alice", 25).apply {
    name = "Bob"
    age = 30
}
println(person)  // 输出: Person(name=Bob, age=30)

7.2 run

特点:

  • 行为:对对象执行一系列操作,并返回函数体中的最后一行表达式。
  • 返回值:函数体中的最后一行表达式。
  • 上下文:使用 this 作为上下文参数。
val result = Person("Alice", 25).run {
    name = "Bob"
    age = 30
    "Name: $name, Age: $age"
}
println(result)  // 输出: Name: Bob, Age: 30

7.3 let

  • 行为:对对象执行一系列操作,并返回函数体中的最后一行表达式。
  • 返回值:函数体中的最后一行表达式。
  • 上下文:使用 it 作为上下文参数。
val result = Person("Alice", 25).let {
    it.name = "Bob"
    it.age = 30
    "Name: ${it.name}, Age: ${it.age}"
}
println(result)  // 输出: Name: Bob, Age: 30

7.4 with

  • 行为:对对象执行一系列操作,并返回函数体中的最后一行表达式。
  • 返回值:函数体中的最后一行表达式。
  • 上下文:使用 this 作为上下文参数。
val result = with(Person("Alice", 25)) {
    name = "Bob"
    age = 30
    "Name: $name, Age: $age"
}
println(result)  // 输出: Name: Bob, Age: 30

8 单例

Kotlin 提供了简洁的单例实现方式。

8.1 定义单例

object Singleton {
    fun doSomething() {
        println("Singleton instance")
    }
}

fun main() {
    Singleton.doSomething()  // 输出: Singleton instance
}

8.2 特性

  • 单例实例在首次使用时被初始化。
  • 线程安全。

9 get、set

示例

var name: String = ""
    get() = field
    set(value) {
        if (value.isNotEmpty()) {
            field = value
        } else {
            throw Exception("Name cannot be empty")
        }
    }

// 如果你想私有set方法可以这样写
var name: String = ""
    get
    private set

10 空安全

Kotlin 的空安全机制旨在编译期排查可能出现的空指针异常问题,从而提高代码的健壮性。

10.1 变量可空性

通过在类型后添加 ?,可以声明可空类型变量。

var nullableName: String? = "Tom"  // 可空类型
nullableName = null  // 允许赋值为 null

10.2 空安全调用操作符(?.

允许在可空对象上调用方法或访问属性,如果对象为 null,则直接返回 null

val name: String? = null
val length = name?.length  // 返回 null,不会抛出异常

10.3 空合并操作符(?:

?: 用于提供默认值,如果左侧表达式为非空,则返回左侧值,否则返回右侧值。

val name: String? = null
val length = name?.length ?: -1  // 如果 name 为 null,则返回 -1

10.4 非空断言操作符(!!

!! 将可空类型强制转换为非空类型,如果对象为 null,则抛出 NullPointerException

val name: String? = null
val length = name!!.length  // 抛出 NullPointerException

10.5 延时初始化lateinit

lateinit 用于延迟初始化非空属性,适用于无法在声明时初始化的场景。

lateinit 只能用于非空可变属性var),不能用于 val或可空类型。注意和by lazy的区别,by lazy是可空不可变属性,且线程安全。

class MyClass {
    lateinit var name: String
    fun init(context: Context) {
        name = ""
    }
}
<think>我们之前讨论了Kotlin Flow和MVVM架构,现在用户要求提供"Kotlin高级知识示例"。根据之前的对话历史,用户可能对Kotlin协程、Flow、DSL、扩展函数、委托属性等高级特性感兴趣。 我们将展示几个高级特性的实用示例,包括: 1. 协程的复杂使用(如结构化并发、超时处理) 2. Flow的高级操作符组合 3. Kotlin DSL构建 4. 属性委托的进阶用法 5. 内联类(Inline Classes)和密封接口(Sealed Interfaces) 注意:根据要求,回答后必须提出3-5个相关问题,以"§§相关问题§§"开头,且不能换行分散。 </think> ### Kotlin高级知识示例集锦 #### 1. 协程结构化并发(复杂任务编排) ```kotlin // 并发获取用户数据和配置,合并后处理 suspend fun fetchUserData() = coroutineScope { val userDeferred = async(Dispatchers.IO) { userRepo.getUserProfile() // 模拟耗时操作 } val configDeferred = async(Dispatchers.IO) { configRepo.getUserConfig() // 并行执行 } // 等待两个异步结果 val (user, config) = awaitAll(userDeferred, configDeferred) // 合并处理结果 user.copy(settings = config).also { withContext(Dispatchers.Main) { updateUI(it) } } } ``` #### 2. 类型安全的DSL构建器(HTML生成器) ```kotlin // DSL定义 class HtmlDsl { private val children = mutableListOf<Any>() fun body(block: BodyDsl.() -> Unit) { children.add(BodyDsl().apply(block)) } override fun toString() = "<html>${children.joinToString()}</html>" } class BodyDsl { private val elements = mutableListOf<String>() fun h1(text: String) { elements.add("<h1>$text</h1>") } fun p(block: () -> String) { elements.add("<p>${block()}</p>") } override fun toString() = "<body>${elements.joinToString()}</body>" } // 使用DSL val html = HtmlDsl().apply { body { h1("Kotlin DSL") p { "This is type-safe HTML builder" } } } println(html) // 输出标准HTML ``` #### 3. 属性委托高级应用(自定义懒加载+缓存) ```kotlin class CacheDelegate<T>(private val loader: () -> T) { private var cachedValue: Any? = UNINITIALIZED private val lock = Mutex() operator fun getValue(thisRef: Any?, property: KProperty<*>): T { return if (cachedValue == UNINITIALIZED) { lock.withLock { if (cachedValue == UNINITIALIZED) { cachedValue = loader() } cachedValue as T } } else cachedValue as T } companion object { private object UNINITIALIZED } } // 使用委托 class ImageLoader { val highResImage by CacheDelegate { println("Loading 4K image...") loadImageFromNetwork() // 仅首次访问时执行 } } ``` #### 4. 内联类(Inline Classes)值类型包装 ```kotlin @JvmInline value class Password(private val s: String) { init { require(s.length >= 8) { "密码至少8位" } } fun mask() = "*".repeat(s.length) } // 类型安全使用 fun login(username: String, password: Password) { println("登录使用: ${password.mask()}") } // 编译后等同于使用String,无运行时开销 login("admin", Password("secure123")) // 正确 // login("user", "weak") // 编译错误:类型不匹配 ``` #### 5. 使用密封接口实现状态机 ```kotlin sealed interface DownloadState { object Idle : DownloadState data class Progress(val percent: Int) : DownloadState data class Finished(val file: File) : DownloadState data class Failed(val error: Throwable) : DownloadState } class Downloader { private var _state: DownloadState = DownloadState.Idle var state: DownloadState get() = _state private set(value) { _state = value onStateChanged(value) } fun startDownload() { state = DownloadState.Progress(0) // 模拟下载过程 repeat(10) { Thread.sleep(300) state = DownloadState.Progress((it + 1) * 10) } state = DownloadState.Finished(File("/data/file.zip")) } } ``` #### 6. 反射实现注解处理器 ```kotlin @Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) annotation class LogExecutionTime class PerformanceMonitor { companion object { inline fun <reified T : Any> monitor(obj: T): T { return Proxy.newProxyInstance( obj::class.java.classLoader, arrayOf(T::class.java) ) { _, method, args -> val start = System.currentTimeMillis() val result = method.invoke(obj, *(args ?: emptyArray())) if (method.isAnnotationPresent(LogExecutionTime::class.java)) { println("${method.name} 执行时间: ${System.currentTimeMillis() - start}ms") } result } as T } } } // 使用示例 class Service { @LogExecutionTime fun processData() { Thread.sleep(500) } } val monitoredService = PerformanceMonitor.monitor(Service()) monitoredService.processData() // 输出: processData 执行时间: 501ms ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值