kotlin by关键字

在Kotlin中,by 关键字有多个用途,但最常见用于实现委托模式。委托模式是一种设计模式,它允许一个对象将部分职责委托给另一个对象。在Kotlin中,by 关键字提供了一种简洁的语法,使得委托的实现变得更加轻松。

委托模式概述

在委托模式中,有两个主要角色:

委托类(Delegated Class): 持有实际的工作对象,负责将部分职责委托给这个对象。

委托属性(Delegated Property): 在委托类中声明的属性,使用 by 关键字将其委托给其他类。

by关键字的工作原理

当使用 by 关键字将属性委托给其他类时,编译器会在后台生成一些额外的代码,实际上是将属性的 getter 和 setter 方法委托给特定的委托类。下面是一个简单的例子来说明 by 关键字的工作原理:

interface Printer {

    fun print(message: String)

}

class DefaultPrinter : Printer {

    override fun print(message: String) {

        println("Default: $message")

    }

}

class CustomPrinter(private val delegate: Printer) : Printer by delegate

fun main() {

    val customPrinter = CustomPrinter(DefaultPrinter())

    customPrinter.print("Hello, Kotlin!")

}

在这个例子中,CustomPrinter 类通过 by 关键字将 Printer 接口的实现委托给了 DefaultPrinter 类。编译器会生成类似下面的代码:

class CustomPrinter(private val delegate: Printer) : Printer {

    override fun print(message: String) {

        delegate.print(message)

    }

}

实际上,CustomPrinter 中的 print 方法被委托给了 DefaultPrinter 的 print 方法。

自定义委托类

除了使用接口作为委托的对象外,我们还可以自定义委托类。自定义委托类需要实现属性委托的接口,即具备 getValue 和 setValue 方法。以下是一个简单的自定义委托类的例子:

import kotlin.reflect.KProperty

class CustomDelegate {

    private var value: String = ""

    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {

        println("Getting value: $value")

        return value

    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: String) {

        println("Setting value: $newValue")

        value = newValue

    }

}

class Example {

    var customProperty: String by CustomDelegate()

}

fun main() {

    val example = Example()

    example.customProperty = "Hello, Kotlin!"

    println(example.customProperty)

}

在上面的例子中,CustomDelegate 类实现了属性委托的接口,通过重写 getValue 和 setValue 方法实现了属性的读取和设置。Example 类中的 customProperty 属性通过 by 关键字委托给了 CustomDelegate 类。

lazy原理

有了上面的基础,再来看lazy的实现就非常简单。

lazy 是 Kotlin 标准库中的一个函数,用于实现延迟初始化。它的主要作用是将一个 lambda 表达式作为参数传递给 lazy 函数,该 lambda 表达式将在首次访问属性时执行,并且只会执行一次。lazy 返回一个 Lazy 类型的实例,该实例包含一个被委托的属性,以及相应的初始化逻辑。

以下是 lazy 的简化实现原理,为了更好地理解,我们将采用伪代码的形式:

class Lazy<T>(private val initializer: () -> T) {

    private var value: T? = null

    private var isInitialized: Boolean = false

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {

        if (!isInitialized) {

            value = initializer()

            isInitialized = true

        }

        return value!!

    }

}

fun <T> lazy(initializer: () -> T): Lazy<T> = Lazy(initializer)

上述代码中,我们定义了一个 Lazy 类,它接受一个 lambda 表达式 initializer,这个 lambda 表达式包含了属性首次访问时的初始化逻辑。Lazy 类包含一个泛型参数 T,表示被委托的属性的类型。

value 存储被委托属性的值,初始值为 null。

isInitialized 用于追踪属性是否已经被初始化。

Lazy 类还实现了 getValue 操作符函数,这是属性委托的关键。当被委托的属性首次被访问时,getValue 函数会执行 initializer lambda 表达式,初始化属性的值,并将 isInitialized 设置为 true。之后,再次访问该属性时,直接返回已经初始化过的值。

最后,我们通过 lazy 函数创建了一个 Lazy 类的实例,用于实际的属性委托。在实际使用中,lazy 函数可以直接作为属性的委托,如下所示:

val myProperty: String by lazy {

    println("Initializing myProperty")

    "Hello, Kotlin!"

}

fun main() {

    println(myProperty) // 第一次访问,会执行初始化逻辑

    println(myProperty) // 后续访问,直接返回已初始化的值

}

在上述例子中,myProperty 的初始化逻辑只在首次访问时执行,之后的访问直接返回已经初始化的值。

总结

通过 by 关键字,Kotlin 提供了一种优雅而强大的委托模式实现方式。无论是通过接口还是自定义委托类,都能够轻松地实现代码的重用和解耦。了解 by 关键字的实现原理有助于更深入地理解 Kotlin 的委托模式,并在实际开发中更加灵活地运用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容