Kotln 属性委托

92 阅读2分钟

在 Kotlin 中,by :: 是一种‌属性间委托‌的语法糖,用于直接将一个属性的读写操作委托给另一个已存在的属性。通过这种机制,两个属性将共享同一份数据存储空间,操作任一属性会同步影响另一方。 委托类 委托的是接口的方法 委托属性 委托的是属性的set get


一、语法解析

示例代码:

var number: Float by ::floatValue
  • ‌**floatValue**‌:被委托的已有属性(需与 number 同属一个类或作用域)。
  • :: 操作符‌:表示委托关系,系统会自动生成 getValuesetValue 逻辑,无需手动实现委托类7。

二、核心特性

特性说明
数据共享委托方(number)与被委托方(floatValue)共享同一数据源,修改一方会同步另一方7。
简化代码避免重复定义存储逻辑,适用于需要多属性映射同一底层数据的场景(如别名属性)78。
内置实现基于 Kotlin 标准库的 PropertyDelegateProvider 自动处理委托逻辑,无需自定义委托类7。

三、代码示例

class Simple04 {

    // var 可读 可改 内部会有 set get           val 只有get 只读
    var floatValue : Float = 757567.65f
        set(v) {
            field = v
            println("你设置了 floatValue哦 v:$v")
        }
        get() {
            println("你获取了 floatValue哦")
            return field
        }

    var number : Float by ::floatValue
        /*set(v) {  相当于,隐式的有这段代码哦
            field = v
            println("你设置了floatValue哦 v:$v")
        }
        get() {
            println("你获取了floatValue哦")
            return field
        }*/
    /*
    背后实现的原理:是通过单例来实现的
    public final class Simple04 {
        // 实例 方便访问 getFloatValue  setFloatValue 的实例
        private final KMutableProperty0 number$delegate = new Simple04$number$2((Simple04)this);

        private float floatValue = 8768979.0F;

        public final float getFloatValue() {
          String var1 = "你获取了floatValue哦";
          System.out.println(var1);
          return this.floatValue;
        }

       public final void setFloatValue(float v) {
          this.floatValue = v;
          String var2 = "你设置了floatValue哦 v:" + v;
          System.out.println(var2);
       }

        // 用户在读取 number 调用 getNumber ---> 实例 ---> getFloatValue
        public final float getNumber() {
          KProperty0 var1 = (KProperty0)this.number$delegate;
          Object var3 = null;
          return ((Number)var1.get()).floatValue();
       }

       // 用户在赋值 number 调用 setNumber ---> 实例 ---> setFloatValue
       public final void setNumber(float var1) {
          KMutableProperty0 var2 = this.number$delegate;
          Object var4 = null;
          Float var5 = var1;
          var2.set(var5);
       }
    }
 */
}

fun main() {
    val simple04 = Simple04()
    simple04.number = 99999.0f  // 我给number赋值【用户在赋值 number 调用 setNumber ---> 实例 ---> setFloatValue】
    println(simple04.number) // 我读取number【/用户在读取 number 调用 getNumber ---> 实例 ---> getFloatValue】
}
  • 输出结果‌:

你获取了 floatValue哦

757567.6


四、应用场景

  1. 属性别名
    为已有属性提供更直观的命名(如 width 委托给 size.width)。
  2. 数据同步
    多个属性需要实时同步同一数据源时(如 UI 控件与数据模型绑定)。
  3. 代码精简
    替代显式委托类的模板代码,简化逻辑重复场景的实现。

五、注意事项

  1. 作用域限制
    被委托属性(如 floatValue)需与委托属性(如 number)在‌同一类或作用域‌内。
  2. 类型一致性
    委托属性和被委托属性的类型必须兼容(相同类型或其父类)6。
  3. 仅限 var 属性
    by :: 语法要求委托属性必须是可变属性(var),不可用于 val

通过 by ::,Kotlin 提供了一种简洁高效的方式实现属性间的数据共享与逻辑复用,适用于需要简化属性映射关系的场景78。