什么是Kotlin支持领域?

Yud*_*rya 73 android kotlin kotlin-android-extensions

作为一名Java开发人员,支持领域的概念对我来说有点陌生.鉴于:

   class Sample {
        var counter = 0 // the initializer value is written directly to the backing field
        set(value) {
            if (value >= 0) field = value
        }
    }
Run Code Online (Sandbox Code Playgroud)

这个支持领域有什么用?Kotlin博士说:Kotlin的课程不能有字段.但是,有时在使用自定义访问器时需要有一个支持字段.为什么?在setter中使用属性名称本身的区别是什么.

    class Sample {        
        var counter = 0
        set(value) {
            if (value >= 0) this.counter = value // or just counter = value?
        }
    }
Run Code Online (Sandbox Code Playgroud)

gle*_*e8e 71

因为,如果你没有field关键字,你将无法在get()或中实际设置/获取值set(value).它使您可以访问自定义访问器中的支持字段.

这是您的示例的等效Java代码:

class Sample {
    private int counter = 0;
    public void setCounter(int value) {
        if (value >= 0) setCounter(value);
    }
    public int getCounter() {
        return counter;
    }
}
Run Code Online (Sandbox Code Playgroud)

显然这不好,因为setter只是一个infinte recursion本身,从来没有改变任何东西.记得在kotlin中,无论何时你写foo.bar = value它都会被翻译成一个setter call而不是a PUTFIELD.


编辑:Java有字段,而Kotlin有属性,这是一个比字段更高级别的概念.

有两种类型的属性:一种具有支持字段,一种没有.

具有支持字段的属性将以字段的形式存储该值.该字段使存储值可以存储在内存中.这种属性的一个例子是first和的second属性Pair.该属性将改变内存中的表示形式Pair.

没有后备字段的属性必须以其他方式存储其值,而不是直接将其存储在内存中.它必须从其他属性或对象本身计算.此类属性的一个示例是indices扩展属性List,它不是由字段支持,而是基于size属性的计算结果.所以它不会改变内存中的表示List(它根本不能做,因为Java是静态类型的).

  • 很多模糊的解释。为什么我们不能简单地说,“字段”更像是一个指针或对现有成员变量的引用。由于“get/set”紧跟在“counter”之后,因此“field”关键字是对“counter”的引用。正确的? (3认同)

the*_*ger 15

最初,我也很难理解这个概念.所以让我借助一个例子向你解释一下.

考虑一下这个Kotlin课程

class DummyClass {
    var size = 0;
    var isEmpty
        get() = size == 0
        set(value) {
            size = size * 2
        }
}
Run Code Online (Sandbox Code Playgroud)

现在,当我们查看代码时,我们可以看到它有2个属性,即 - size(使用默认访问器)和isEmpty(使用自定义访问器).但它只有1个字段即size.要了解它只有1个字段,让我们看看这个类的Java等价物.

转到工具 - > Kotlin - >在Android Studio中显示Kotlin ByteCode.单击"反编译".

   public final class DummyClass {
   private int size;

   public final int getSize() {
      return this.size;
   }

   public final void setSize(int var1) {
      this.size = var1;
   }

   public final boolean isEmpty() {
      return this.size == 0;
   }

   public final void setEmpty(boolean value) {
      this.size *= 2;
   }
}
Run Code Online (Sandbox Code Playgroud)

显然,我们可以看到java类只有getter和setter函数isEmpty,并且没有声明它的字段.类似地,在Kotlin中,没有属性的支持字段isEmpty,因为该属性根本不依赖于该字段.因此没有支持领域.


现在让我们删除自定义的getter和setter isEmpty属性.

class DummyClass {
    var size = 0;
    var isEmpty = false
}
Run Code Online (Sandbox Code Playgroud)

而上述类的Java等价物是

public final class DummyClass {
   private int size;
   private boolean isEmpty;

   public final int getSize() {
      return this.size;
   }

   public final void setSize(int var1) {
      this.size = var1;
   }

   public final boolean isEmpty() {
      return this.isEmpty;
   }

   public final void setEmpty(boolean var1) {
      this.isEmpty = var1;
   }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们看到了两个领域sizeisEmpty.isEmpty是一个支持字段,因为isEmpty属性的getter和setter 依赖于它.

  • 很好的解释。谢谢 (4认同)
  • 真的,谢谢你的解释。我也是从 Java 来到 Kotlin,*属性* 的概念对我来说是新的。但感谢您和指导,我已经理解了。:) (2认同)
  • 我喜欢这个答案,它诚实地引用了事实。我还是有疑问,因为**C#**不需要`field`关键字,有没有可能Kotlin的语言改进会去掉这个奇怪的`field`关键字,避免那些无助的灵魂陷入无限的深渊递归? (2认同)

Mar*_*cha 9

备份字段适用于运行验证或触发状态更改事件.想想您将代码添加到Java setter/getter的时间.在类似的场景中,支持字段会很有用.当您需要控制或了解setter/getter时,您可以使用支持字段.

在使用字段名称本身分配字段时,您实际上正在调用setter(即set(value)).在你拥有的例子中,this.counter = value将递归到set(value)直到我们溢出堆栈.使用field绕过setter(或getter)代码.

  • 抱歉,您的解释包含需要解释的术语。然后,您首先引用了一个 Java 场景,然后突然毫无警告地切换到实际的 Kotlin 语句。Kotlin 对关键字“field”的需求不在 **C#** 中,因此我们需要比您在此处引用的解释更好的解释。 (2认同)