2017-04-05 250 views
36

作为一名Java开发人员,后台字段的概念对我来说有点陌生。鉴于:什么是科特林支持领域?

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

这是什么支持领域的好处? Kotlin docs说:Kotlin中的类不能有字段。但是,有时在使用定制访问器时需要有后台字段。为什么?在setter中使用属性名称本身的区别是什么,例如。

class Sample {   
     var counter = 0 
     set(value) { 
      if (value >= 0) this.counter = value // or just counter = value? 
     } 
    } 
+3

当然,作为Java开发人员,这个概念是每天使用一百万次的东西:)所有这些'private SomeClass字段;' – Strelok

+4

在setter中使用属性本身会导致无限递归,因为将一些值赋给属性会一直打电话给二传手。 – funglejunk

+0

@Strelok我的不好....我在假设阅读Kotlin的文档时'this.counter = value'与Java相同。 –

回答

36

因为,说如果你没有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; 
    } 
} 

显然,这是不好的,因为二传手只是一个infinte递归到自身,从来没有改变任何东西。每当你写入foo.bar = value时,请记住在kotlin中,它将被翻译为setter调用而不是PUTFIELD


编辑:科特林具有性质而Java有字段,这是比场相当更高层次的概念。

有两种类型的属性:一种带有后台字段,另一种没有。

具有后台字段的属性将以字段的形式存储该值。该领域使存储在内存中的价值成为可能。此类属性的一个示例是Pairfirstsecond属性。该属性将改变Pair的内存中表示。

没有后台字段的属性必须以其他方式存储它们的值,而不是直接将其存储在内存中。它必须从其他属性或对象本身进行计算。此属性的一个示例是Listindices扩展特性,该特性不支持字段,而是基于size属性的计算结果。所以它不会改变List的内存表示(它根本无法完成,因为Java是静态类型的)。

+0

感谢您的回答!我的坏...我假设'this.counter = value'与java等价。 –

7

备份字段非常适合在状态更改时运行验证或触发事件。想想您将代码添加到Java setter/getter的时间。在类似的情况下,备份字段会很有用。当你需要控制或对setter/getters有可见性时,你会使用后备字段。

当为字段赋予字段名称本身时,实际上是调用setter(即set(value))。在你的例子中,this.counter = value会递归到set(value)中,直到我们溢出堆栈。使用field可绕过setter(或getter)代码。

1

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

考虑这个科特林级

class DummyClass { 
    var size = 0; 
    var isEmpty 
     get() = size == 0 
     set(value) { 
      size = size * 2 
     } 
} 

现在,当我们在看代码,我们可以看到它有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; 
    } 
} 

显然,我们可以看到,在Java类只有getter和setter函数为isEmpty,并没有宣布它领域。同样在Kotlin中,由于该属性完全不依赖于该字段,因此没有属性isEmpty的后台字段。因此没有支持领域。


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

class DummyClass { 
    var size = 0; 
    var isEmpty = false 
} 

和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; 
    } 
} 

这里我们可以看到两个领域sizeisEmptyisEmpty是后台字段,因为isEmpty属性的获取器和设置器取决于它。