by 和by lazy 懒加载

0 阅读2分钟

一、by 两种使用场景

  1. 委托类(类委托)class A : B by C把接口方法实现,全权委托给另一个对象去执行,简化代码复用。
  2. 委托属性var/val 变量:类型 by 委托类把属性的 get/set 逻辑交给委托类实现。

1、类委托 by

意思:自己不想写方法,直接交给别人帮我干活

1. 先写一个干活的接口

kotlin

interface Drive {
    fun drive() // 开车
}
2. 找一个会开车的人

kotlin

class Driver : Drive {
    override fun drive() {
        println("老司机稳稳开车")
    }
}
3. 老板不会开车,委托司机开

kotlin

// 老板把开车这件事,全权委托给司机
class Boss(driver: Drive) : Drive by driver
4. 调用

kotlin

fun main(){
    val laoban = Boss(Driver())
    laoban.drive() // 直接司机执行
}

直白理解:我实现接口,但我不写代码,交给别人实现

2、属性委托 by(最常用)

一句话理解

变量的 get 和 set,交给别人去做


超简单例子(背这个)

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

val p = Person()

p.name = "张三"   // 走 setValue
println(p.name)   // 走 getValue

输出

plaintext

赋值了:张三
我是取值

二、by lazy 懒加载(必考)

1. 用法

kotlin

val name: String by lazy {
    "初始化值"
}

第一次调用才执行 lambda 初始化,之后直接拿缓存值

2. 三种模式

kotlin

// 1. 线程安全(默认),多线程单例初始化
by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { }

// 2. 不加锁,单线程使用最快
by lazy(LazyThreadSafetyMode.NONE) { }

// 3. 多线程并行,谁先初始化谁生效
by lazy(LazyThreadSafetyMode.PUBLICATION) { }

3. 底层实现原理(面试背诵)

  1. 本质是属性委托,底层实现 Lazy 接口

  2. 内部用volatile 标记缓存值,保证可见性

  3. 内部做空判断

    • 变量未初始化 → 执行 lambda 赋值
    • 已初始化 → 直接返回已有值
  4. 只初始化一次,延迟加载,节省内存

  5. 只能修饰 val 只读属性,不能用于 var

4. 特点

  • 延迟初始化,用到才创建
  • 线程安全默认实现
  • 全局单例效果,全局共用同一个对象

三、极简面试答案

  1. by 关键字用于类委托属性委托
  2. by lazy 是属性委托最常用实现,延迟懒加载
  3. 原理:首次访问执行初始化并缓存,后续直接取值,内部通过空校验 + 线程安全策略实现,仅支持只读 val 属性。