当前位置: 首页 > ds >正文

Kotlin属性委托

在 Kotlin 中,委托不仅适用于类,也适用于属性。与传统属性直接由字段支持不同,委托属性将 get 和 set 的职责交给了一段单独的代码块。这样做的好处是可以将某些通用功能抽象出来,供多个相似的属性共享,从而实现属性逻辑的复用,提升代码的效率和可维护性


属性委托示例

我们来看一个名为 Example 的类,其中包含两个 String 类型的属性:firstPropsecondProp。如果我们希望这两个属性具有相同的格式化规则,可以为它们各自实现一个 setter 方法:

class Example {var firstProp: String = ""set(value) {// 移除所有元音,并将字符串转为大写field = value.replace(Regex("[aeiouAEIOU]"), "").uppercase()}var secondProp: String = ""set(value) {// 移除所有元音,并将字符串转为大写field = value.replace(Regex("[aeiouAEIOU]"), "").uppercase()}
}
代码说明

在这个例子中,我们给两个属性都定义了 set 函数,用来移除输入值中的所有元音字母并将其转换为大写。然而,这种做法会导致代码重复,不利于测试和维护。

一种更高效的写法是将 setter 委托出去,代码如下:

class Example {var firstProp: String by Formatter()var secondProp: String by Formatter()
}
代码说明

委托属性的声明方式是通过 by 关键字指定使用的委托对象。语法为:

val/var <属性名>: <类型> by <委托实例>

接下来我们看看如何实现这个 Formatter 委托类。


实现属性委托

属性委托类必须实现 getValue() 方法,若属性为 var 类型,还需实现 setValue() 方法。

在上面的例子中,Formatter 是负责控制 firstPropsecondProp 的 getter 和 setter 的委托类,实现如下:

import kotlin.reflect.KPropertyclass Formatter {private var value: String = ""operator fun getValue(thisRef: Any?, property: KProperty<*>): String {return value}operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {this.value = value.replace(Regex("[aeiouAEIOU]"), "").uppercase()}
}
代码说明

自定义属性委托类时,需要定义两个操作符函数:

  • getValue():负责返回属性的当前值;

  • setValue():负责设置属性的新值。

这两个函数可以访问包含该属性的类(thisRef)以及属性本身的元数据(KProperty)。

参数详解示例

import kotlin.reflect.KPropertyclass AnotherExample {val stringProp: String by Delegate()fun foo(): String = ""
}class Delegate {private var curValue = ""operator fun getValue(thisRef: AnotherExample, property: KProperty<*>): String {println(thisRef.stringProp + thisRef.foo()) // 可通过 thisRef 访问其他成员return curValue}
}
代码说明

在这个例子中,我们将一个只读属性 val 委托给 Delegate 类,因此只需要提供 getValue() 方法。

  • thisRef 参数表示拥有该属性的对象(这里是 AnotherExample 实例)。

  • property 参数是一个 KProperty 实例,用于访问属性的元信息,例如:

println(property.name) // 输出属性名 stringProp

如果将属性改为 var,则还需要提供 setValue() 方法:

class AnotherExample {var stringProp: String by Delegate()
}class Delegate {private var curValue = ""operator fun getValue(thisRef: AnotherExample, property: KProperty<*>): String {return curValue}operator fun setValue(thisRef: AnotherExample, property: KProperty<*>, value: String) {println("属性 ${property.name} 的新值为: $value")curValue = value}
}

匿名委托对象(Anonymous Delegates)

Kotlin 允许你使用匿名对象来创建委托,而不需要额外定义一个类。只需要使用标准库提供的接口即可:

import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
  • ReadOnlyProperty 接口只需实现 getValue()

  • ReadWriteProperty 继承自 ReadOnlyProperty 并添加了 setValue() 方法。

示例:

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KPropertyfun anonymousDelegate() = object : ReadWriteProperty<Any?, String> {var curValue = ""override fun getValue(thisRef: Any?, property: KProperty<*>): String {return curValue}override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {curValue = valueprintln("属性 ${property.name} 的新值是: $value")}
}fun main() {val readOnlyString: String by anonymousDelegate()var readWriteString: String by anonymousDelegate()readWriteString = "Hello!" // 输出:属性 readWriteString 的新值是: Hello!
}
代码说明

这个例子中我们定义了一个 anonymousDelegate() 函数,返回一个匿名对象,它实现了 ReadWriteProperty 接口。你可以在函数中局部使用这样的委托对象,这就是 Kotlin 所支持的 局部委托属性(local delegated properties)


委托给另一个属性

Kotlin 还允许你将一个属性委托给另一个属性。示例:

class Example {private var _counter = 0var counter: Intget() = _counterset(value) {_counter = valueprintln("Counter 设置为 $value")}var anotherCounter: Int by this::counter
}fun main() {val example = Example()example.anotherCounter = 5 // 输出:Counter 设置为 5
}
代码说明

anotherCounter 使用 by this::counter 将委托权交给了 counter 属性。因此访问 anotherCounter 实际上等价于访问 counter

如果要委托给另一个类的属性,只需将 this 替换为那个类的实例名即可。


最佳实践

  1. 尽量使用标准库中的委托类
    Kotlin 标准库提供了 lazyobservablemap-based 等常用委托,能减少样板代码,建议优先使用。

  2. 保持委托单一职责
    委托类应只处理一种逻辑,避免变得过于复杂,难以测试。

  3. 不要滥用委托机制
    并不是所有属性都需要委托。只有在确实能提高复用、减少重复代码时才建议使用。


总结

本文介绍了 Kotlin 中强大的属性委托机制。我们学习了:

  • 如何使用 getValue()setValue() 实现自定义委托;

  • 如何使用匿名对象来创建委托;

  • 如何将属性委托给另一个属性;

  • 以及推荐的使用最佳实践。

属性委托不仅使代码更加清晰和复用性更强,还可以增强系统的扩展能力,是 Kotlin 提供的一项非常实用的语言特性。

http://www.xdnf.cn/news/17218.html

相关文章:

  • 探秘MOBILITY China 2026,新能源汽车与智慧出行的未来盛宴
  • React18 严格模式下的双重渲染之谜
  • 嵌入式硬件中运放的基本控制原理
  • 2025金九银十Java后端面试攻略
  • 天津大学2024-2025 预推免 机试题目(第二批)
  • 400V降24V,200mA,应用领域:从生活到工业的 “全能电源管家”
  • C++面向对象编程基础:从类定义到封装机制详解
  • 深度学习-卷积神经网络CNN-填充与步幅
  • 最新基于Python科研数据可视化实践技术
  • 【人工智能99问】什么是Post-Training,包含哪些内容?(19/99)
  • Next Terminal 实战:内网无密码安全登录
  • MCP进阶:工业协议与AI智能体的融合革命
  • Redis之Hash和List类型常用命令
  • VGMP(VRRP Group Management Protocol)VRRP组管理协议
  • Druid学习笔记 02、快速使用Druid的SqlParser解析
  • Solidity全局变量与安全实践指南
  • python中的字典
  • 雷达系统工程学习:自制极化合成孔径雷达无人机
  • bypass
  • SelectDB:新一代实时数仓的核心引擎与应用实战
  • 机器学习——基本算法
  • 笛卡尔坐标
  • Java 中 BigDecimal、Float、Double 的取整与保留小数处理方法详解
  • 简要探讨大型语言模型(LLMs)的发展历史
  • Android进程基础:Zygote
  • Linux 磁盘管理与分区配置
  • 【2025WACV-最佳论文】RayGauss:基于体积高斯的光线投射,用于逼真的小说视图合成
  • (JAVA)自建应用调用企业微信API接口,设置企业可信IP
  • 前端开发(HTML,CSS,VUE,JS)从入门到精通!第五天(jQuery函数库)
  • 使用1panel将http升级至https的过程