Kotlin 向我解释了 Backing Fields

Kotlin explain me about Backing Fields

一直在看Kotlin官方教程。我遇到了名为 Backing Fields

的主题

它说,

Classes in Kotlin cannot have fields. However, sometimes it is necessary to have a backing field when using custom accessors. For these purposes, Kotlin provides an automatic backing field which can be accessed using the field identifier:

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

以上内容来自this official link

我的问题是,"field" 是否指向计数器变量?

有人可以给我提供一个支持字段的例子或者用一个可以理解的词来描述我吗?

它是如何工作的,让我们通过一个例子来理解,考虑这个

class Person {
   var name: String = ""
}

如果未指定任何内容,则 属性(name) 使用默认值 getter 和 setter。当然,它可以 修改为 运行 您需要的任何自定义行为,而无需更改 现有代码:

所以如果想要将自定义行为设置为名称 属性 而不是我们在上面 class 修改为这个

class Person {

   var name: String = ""
   get() = field.toUpperCase()
   set(value) {
     field = "Name: $value"
  }


}

如果 属性 需要在自定义 getter 或 setter 中访问它自己的值(如 例),它需要创建一个 支持字段 。它可以通过使用字段访问,一个 保留字,当编译器发现时会自动创建 它正在被使用。

A Backing Field is just a field that will be generated for a property in a class only if it uses the default implementation of at least one of the accessors

仅当 属性 使用 getter/setter 的默认实现时才会生成支持字段。如果你以Java的视角看到下面的代码。它看起来是正确的。但是在 "kotlin" 中它会抛出异常。

  class User{ 
       var firstName : String //backing field generated
      get() = firstName 
      set(value) {
           firstName = value
      } 
      var lastName : String //backing field generated 
      get() = lastName 
      set(value) {
           lastName = value
      }
      val name : String //no backing field generated 
      get() = "{$firstName $lastName}" 
      var address : String = "XYZ" //^because there is no default //^implementation of an accessor 
 }

在 Kotlin 中,上面的代码片段将抛出 Whosebug,因为当我们访问或设置 属性 "first-name" 或 "last name" 时,将调用默认访问器。所以在 Kotlin 中,"user.firstName = "value"" 与 Java 的 "user.setFirstName("value").

相同

因此,当调用 "set(value) {firstName = "value"}" 时,会发生递归调用并且编译器会抛出 Exception 异常,因为我们在 setter 中调用 setter。

此问题的解决方案是用户支持字段。在 Kotlin 中,可以使用访问器中的 "field" 关键字访问支持字段。看看下面更正后的代码片段。

 class User{ 
      var firstName : String get() = field 
      set(value) {
           field = value
      } 
      var lastName : String get() = field 
      set(value) {
           field = value} 
      }
 }

field 关键字允许您在自定义 setter 中分配一个值。在 kotlin 中 counter = 3 将调用 set(3)。所以如果你定义

var counter=0
set(value){
    counter = value
}

它会递归地调用自己,直到你的堆栈已满并且你的进程崩溃。 field关键字直接赋值,无需再次调用setter。

考虑这个class

class SomeClass {
    var counter: Int = 0
        set(value) {
            if (value >= 0) field = value
        }
}

在 Android Studio 中转到 Main menu -> Tools -> Kotlin -> Show Kotlin Bytecode 并在 Kotlin 字节码面板中单击 Decompile

您看到的是 Java 中的等效代码。

public final class SomeClass {
   private int counter;

   public final int getCounter() {
      return this.counter;
   }

   public final void setCounter(int value) {
      if(value >= 0) {
         this.counter = value;
      }
   }
}