什么是Kotlin后台?
作为Java开发人员,后台字段的概念对我来说有点陌生。 鉴于:
class Sample { var counter = 0 // the initializer value is written directly to the backing field set(value) { if (value >= 0) field = value } }
这个后盾有什么好处? Kotlin的文档说: Kotlin中的类不能有字段。 但是,使用自定义访问器时有时需要有后台字段 。 为什么? 在setter中使用属性名称本身的区别是什么,例如。
class Sample { var counter = 0 set(value) { if (value >= 0) this.counter = value // or just counter = value? } }
因为,如果你没有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; } }
显然这并不好,因为二传手本身就是一个无限递归,从不改变任何东西。 记住在kotlin中,只要你写foo.bar = value
,它将被翻译成setter调用而不是PUTFIELD
。
编辑:Kotlin有属性,而Java有字段 ,这是一个比领域更高层次的概念。
有两种types的属性:一种具有后台字段,另一种没有。
具有后台字段的属性将以字段的forms存储该值。 该字段使存储在内存中的价值成为可能。 这种属性的一个例子是Pair
的first
和second
属性。 该属性将改变Pair
的内存表示。
没有后台字段的属性将不得不以其他方式存储它们的值,而不是直接将其存储在内存中。 它必须从其他属性或对象本身进行计算。 此属性的一个示例是List
的indices
扩展属性,它不受字段支持,而是基于size
属性的计算结果。 所以它不会改变List
的内存表示(因为Java是静态types的,所以它根本无法做到)。
备份字段非常适合在状态更改时运行validation或触发事件。 想想你把代码添加到Java setter / getter的时代。 在类似的情况下,备份字段会很有用。 当你需要控制或者对setter / getters有可见性时,你可以使用后备字段。
当为字段赋予字段名称本身时,实际上是调用setter(即set(value)
)。 在你的例子中, this.counter = value
会递归到set(value)中,直到我们溢出堆栈。 使用field
绕过setter(或getter)代码。
最初,我也很难理解这个概念。 所以让我在一个例子的帮助下给你解释一下。
考虑这个Kotlin类
class DummyClass { var size = 0; var isEmpty get() = size == 0 set(value) { size = size * 2 } }
现在,当我们看代码时,我们可以看到它有两个属性,即 – size
(带有默认访问器)和isEmpty
(带有自定义访问器)。 但它只有一个字段即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类只有isEmpty
getter和setter函数,并且没有声明它的字段。 同样在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; } }
这里我们看到字段size
和isEmpty
。 isEmpty
是一个后台字段,因为isEmpty
属性的getter和setter依赖于它。