Como desarrollador de Java, el concepto de campo de respaldo me resulta un poco extraño. Dado:
class Sample {
var counter = 0 // the initializer value is written directly to the backing field
set(value) {
if (value >= 0) field = value
}
}
¿Para qué sirve este campo de apoyo? Los documentos de Kotlin dijeron:
Las clases en Kotlin no pueden tener campos. Sin embargo, a veces es necesario tener un campo de respaldo cuando se utilizan descriptores de acceso personalizados .
¿Por qué? ¿Cuál es la diferencia con el uso del nombre de las propiedades dentro del setter, por ejemplo, *
class Sample {
var counter = 0
set(value) {
if (value >= 0) this.counter = value // or just counter = value?
}
}
android
kotlin
kotlin-android-extensions
Yudhistira Arya
fuente
fuente
this.counter = value
es lo mismo con el equivalente de Java al leer los documentos de Kotlin.Respuestas:
Porque, digamos que si no tiene una
field
palabra clave, no podrá establecer / obtener el valor enget()
oset(value)
. Le permite acceder al campo de respaldo en los descriptores de acceso personalizados.Este es el código Java equivalente de su muestra:
class Sample { private int counter = 0; public void setCounter(int value) { if (value >= 0) setCounter(value); } public int getCounter() { return counter; } }
Aparentemente, esto no es bueno, ya que el colocador es solo una recursividad infinita en sí mismo, sin cambiar nada. Recuerde que en kotlin cada vez que escriba
foo.bar = value
se traducirá en una llamada de setter en lugar de aPUTFIELD
.EDITAR: Java tiene campos mientras que Kotlin tiene propiedades , que es un concepto de nivel bastante más alto que los campos.
Hay dos tipos de propiedades: una con un campo de respaldo y otra sin él.
Una propiedad con un campo de respaldo almacenará el valor en forma de campo. Ese campo hace posible almacenar valor en la memoria. Un ejemplo de dicha propiedad son las propiedades
first
ysecond
dePair
. Esa propiedad cambiará la representación en memoria dePair
.Una propiedad sin un campo de respaldo tendrá que almacenar su valor de otra forma que no sea almacenarlo directamente en la memoria. Debe calcularse a partir de otras propiedades o del propio objeto. Un ejemplo de dicha propiedad es la
indices
propiedad de extensión deList
, que no está respaldada por un campo, sino un resultado calculado basado en lasize
propiedad. Por lo tanto, no cambiará la representación en memoria deList
(lo que no puede hacer en absoluto porque Java está tipado estáticamente).fuente
this.counter = value
es lo mismo con el equivalente de Java.field
es más como un puntero o una referencia a una variable miembro existente? Comoget/set
sigue inmediatamentecounter
, lafield
palabra clave es una referencia acounter
. ¿Derecho?Al principio, a mí también me costó mucho entender este concepto. Déjame explicártelo con la ayuda de un ejemplo.
Considere esta clase de Kotlin
class DummyClass { var size = 0; var isEmpty get() = size == 0 set(value) { size = size * 2 } }
Ahora, cuando miramos el código, podemos ver que tiene 2 propiedades, es decir -
size
(con accesos predeterminados) yisEmpty
(con accesos personalizados). Pero solo tiene 1 campo, es decirsize
. Para entender que solo tiene 1 campo, veamos el equivalente en Java de esta clase.Vaya a Herramientas -> Kotlin -> Mostrar Kotlin ByteCode en Android Studio. Haga clic en Descompilar.
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; } }
Claramente podemos ver que la clase java solo tiene funciones getter y setter para
isEmpty
, y no hay ningún campo declarado para ello. De manera similar, en Kotlin, no hay un campo de respaldo para la propiedadisEmpty
, ya que la propiedad no depende en absoluto de ese campo. Por lo tanto, no hay campo de respaldo.Ahora eliminemos el getter personalizado y el setter de
isEmpty
propiedad.class DummyClass { var size = 0; var isEmpty = false }
Y el equivalente en Java de la clase anterior es
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; } }
Aquí vemos tanto los campos
size
comoisEmpty
.isEmpty
es un campo de respaldo porque el captador y el definidor de laisEmpty
propiedad dependen de él.fuente
field
palabras clave, ¿es posible que una mejora del lenguaje de Kotlin elimine esta extrañafield
palabra clave y evite que las almas indefensas caigan en el abismo de la recursividad infinita?Los campos de respaldo son buenos para ejecutar la validación o desencadenar eventos en el cambio de estado. Piense en las veces que ha agregado código a un setter / getter de Java. Los campos de respaldo serían útiles en escenarios similares. Usaría campos de respaldo cuando necesitara controlar o tener visibilidad sobre los setters / getters.
Al asignar el campo con el nombre del campo en sí, en realidad está invocando al establecedor (es decir
set(value)
). En el ejemplo que tiene,this.counter = value
recurriría a set (value) hasta que desbordemos nuestra pila. El usofield
omite el código de establecimiento (o captador).fuente
field
no está en C #, por lo que necesitamos una mejor explicación que la que citó aquí.Tengo entendido que está usando el identificador de campo como referencia al valor de la propiedad en get o set , cuando desea cambiar o usar el valor de la propiedad en get o set .
Por ejemplo:
class A{ var a:Int=1 get(){return field * 2} // Similiar to Java: public int geta(){return this.a * 2} set(value) {field = value + 1} }
Entonces:
var t = A() println(t.a) // OUTPUT: 2, equal to Java code: println(t.a * 2) t.a = 2 // The real action is similar to Java code: t.a = t.a +1 println(t.a) // OUTPUT: 6, equal to Java code: println(t.a * 2)
fuente
La terminología
backing field
está llena de misterio. La palabra clave utilizada esfield
. Losget/set
métodos, siguen inmediatamente al lado de la variable miembro que está a punto de ser obtenida o configurada a través de este mecanismo de métodos de protección de puertas. Lafield
palabra clave solo se refiere a la variable miembro que se va a establecer u obtener . En la actualidad, Kotlin, no puede hacer referencia a la variable miembro directamente dentro de los métodos de puerta protectora get o set porque, desafortunadamente, resultará en una recursividad infinita porque volverá a invocar el get o set y, por lo tanto, llevará el tiempo de ejecución al abismo profundo.Sin embargo, en C # , puede hacer referencia directamente a la variable miembro dentro de los métodos getter / setter. Estoy citando esta comparación para presentar la idea de que esta
field
palabra clave es la forma en que Kotlin actual la está implementando, pero espero que se elimine en versiones posteriores y nos permita hacer referencia directamente a la variable miembro sin que resulte en una recursividad infinita.fuente