一、by 两种使用场景
- 委托类(类委托)
class A : B by C把接口方法实现,全权委托给另一个对象去执行,简化代码复用。 - 委托属性
var/val 变量:类型 by 委托类把属性的 get/set 逻辑交给委托类实现。
1、类委托 by
意思:自己不想写方法,直接交给别人帮我干活
1. 先写一个干活的接口
kotlin
kotlin
interface Drive {
fun drive() // 开车
}
2. 找一个会开车的人
kotlin
kotlin
class Driver : Drive {
override fun drive() {
println("老司机稳稳开车")
}
}
3. 老板不会开车,委托司机开
kotlin
kotlin
// 老板把开车这件事,全权委托给司机
class Boss(driver: Drive) : Drive by driver
4. 调用
kotlin
kotlin
fun main(){
val laoban = Boss(Driver())
laoban.drive() // 直接司机执行
}
直白理解:我实现接口,但我不写代码,交给别人实现
2、属性委托 by(最常用)
一句话理解
变量的 get 和 set,交给别人去做
超简单例子(背这个)
kotlin
kotlin
class Person {
// name 的取值、赋值 全部交给 Delegate 管理
var name: String by Delegate()
}
// 委托类:专门管变量的 存 和 取
class Delegate {
// 取值
operator fun getValue(thisRef: Any?, prop: KProperty<*>): String {
return "我是取值"
}
// 赋值
operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: String) {
println("赋值了:$value")
}
}
使用
kotlin
scss
val p = Person()
p.name = "张三" // 走 setValue
println(p.name) // 走 getValue
输出
plaintext
赋值了:张三
我是取值
二、by lazy 懒加载(必考)
1. 用法
kotlin
kotlin
val name: String by lazy {
"初始化值"
}
第一次调用才执行 lambda 初始化,之后直接拿缓存值
2. 三种模式
kotlin
csharp
// 1. 线程安全(默认),多线程单例初始化
by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { }
// 2. 不加锁,单线程使用最快
by lazy(LazyThreadSafetyMode.NONE) { }
// 3. 多线程并行,谁先初始化谁生效
by lazy(LazyThreadSafetyMode.PUBLICATION) { }
3. 底层实现原理(面试背诵)
-
本质是属性委托 ,底层实现
Lazy接口 -
内部用volatile 标记缓存值,保证可见性
-
内部做空判断:
- 变量未初始化 → 执行 lambda 赋值
- 已初始化 → 直接返回已有值
-
只初始化一次,延迟加载,节省内存
-
只能修饰 val 只读属性,不能用于 var
4. 特点
- 延迟初始化,用到才创建
- 线程安全默认实现
- 全局单例效果,全局共用同一个对象
三、极简面试答案
- by 关键字用于类委托 和属性委托
- by lazy 是属性委托最常用实现,延迟懒加载
- 原理:首次访问执行初始化并缓存,后续直接取值,内部通过空校验 + 线程安全策略实现,仅支持只读 val 属性。