En tant que développeur Java, le concept de backing field m'est un peu étranger. Donné:
class Sample {
var counter = 0 // the initializer value is written directly to the backing field
set(value) {
if (value >= 0) field = value
}
}
À quoi sert ce champ de support? Les documents de Kotlin ont déclaré:
Les classes à Kotlin ne peuvent pas avoir de champs. Cependant, il est parfois nécessaire d'avoir un champ de sauvegarde lors de l'utilisation d'accesseurs personnalisés .
Pourquoi? Quelle est la différence avec l'utilisation du nom des propriétés lui-même dans le setter, par exemple. *
class Sample {
var counter = 0
set(value) {
if (value >= 0) this.counter = value // or just counter = value?
}
}
android
kotlin
kotlin-android-extensions
Yudhistira Arya
la source
la source
this.counter = value
la même chose avec l'équivalent Java lors de la lecture de la documentation de Kotlin.Réponses:
Parce que, disons que si vous n'avez pas de
field
mot - clé, vous ne pourrez pas réellement définir / obtenir la valeur dansget()
ouset(value)
. Il vous permet d'accéder au champ de sauvegarde dans les accesseurs personnalisés.C'est le code Java équivalent de votre exemple:
class Sample { private int counter = 0; public void setCounter(int value) { if (value >= 0) setCounter(value); } public int getCounter() { return counter; } }
Apparemment, ce n'est pas bon, car le setter n'est qu'une récursion infinie en lui-même, ne changeant jamais rien. Rappelez-vous que dans kotlin, chaque fois que vous écrivez,
foo.bar = value
il sera traduit en un appel de setter au lieu d'unPUTFIELD
.EDIT: Java a des champs tandis que Kotlin a des propriétés , ce qui est un concept de niveau plus élevé que les champs.
Il existe deux types de propriétés: une avec un champ de sauvegarde, une sans.
Une propriété avec un champ de sauvegarde stockera la valeur sous la forme d'un champ. Ce champ permet de stocker la valeur en mémoire. Un exemple d'une telle propriété est les propriétés
first
etsecond
dePair
. Cette propriété modifiera la représentation en mémoire dePair
.Une propriété sans champ de sauvegarde devra stocker sa valeur autrement que de la stocker directement en mémoire. Il doit être calculé à partir d'autres propriétés ou de l'objet lui-même. Un exemple d'une telle propriété est la
indices
propriété d'extension deList
, qui n'est pas soutenue par un champ, mais un résultat calculé basé sur lasize
propriété. Cela ne changera donc pas la représentation en mémoire deList
(ce qu'il ne peut pas faire du tout car Java est typé statiquement).la source
this.counter = value
c'est la même chose avec l'équivalent java.field
ressemble plus à un pointeur ou à une référence à une variable membre existante. Puisque le suivantget/set
suitcounter
donc immédiatement , lefield
mot-clé est une référence àcounter
. Droite?Au début, j'ai aussi eu du mal à comprendre ce concept. Alors laissez-moi vous l'expliquer à l'aide d'un exemple.
Considérez cette classe Kotlin
class DummyClass { var size = 0; var isEmpty get() = size == 0 set(value) { size = size * 2 } }
Maintenant, quand nous regardons le code, nous pouvons voir qu'il a 2 propriétés à savoir -
size
(avec les accesseurs par défaut) etisEmpty
(avec les accesseurs personnalisés). Mais il n'a qu'un seul champ iesize
. Pour comprendre qu'elle n'a qu'un seul champ, voyons l'équivalent Java de cette classe.Allez dans Outils -> Kotlin -> Afficher Kotlin ByteCode dans Android Studio. Cliquez sur Décompiler.
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; } }
Nous pouvons clairement voir que la classe java n'a que des fonctions getter et setter pour
isEmpty
, et il n'y a pas de champ déclaré pour cela. De même, dans Kotlin, il n'y a pas de champ de sauvegarde pour la propriétéisEmpty
, car la propriété ne dépend pas du tout de ce champ. Donc pas de champ de support.Supprimons maintenant le getter et le setter de
isEmpty
propriété personnalisés.class DummyClass { var size = 0; var isEmpty = false }
Et l'équivalent Java de la classe ci-dessus est
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; } }
Ici, nous voyons à la fois les champs
size
etisEmpty
.isEmpty
est un champ de sauvegarde car le getter et le setter pour laisEmpty
propriété en dépendent.la source
field
mot-clé est-il possible qu'une amélioration du langage de Kotlin supprime cefield
mot-clé étrange et évite aux âmes impuissantes de tomber dans l'abîme de la récursivité infinie?Les champs de sauvegarde sont utiles pour exécuter la validation ou déclencher des événements lors d'un changement d'état. Pensez aux fois où vous avez ajouté du code à un setter / getter Java. Les champs de sauvegarde seraient utiles dans des scénarios similaires. Vous utiliseriez des champs de sauvegarde lorsque vous avez besoin de contrôler ou d'avoir une visibilité sur les setters / getters.
Lorsque vous attribuez le champ avec le nom du champ lui-même, vous invoquez en fait le setter (ie
set(value)
). Dans l'exemple que vous avez,this.counter = value
recurse dans set (valeur) jusqu'à ce que nous débordions de notre pile. L'utilisationfield
contourne le code du setter (ou du getter).la source
field
- clé n'est pas en C # , nous avons donc besoin d'une meilleure explication que celle que vous avez citée ici.Ma compréhension utilise l' identificateur de champ comme référence à la valeur de la propriété dans get ou set , lorsque vous souhaitez modifier ou utiliser la valeur de la propriété dans get ou set .
Par exemple:
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} }
Ensuite:
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)
la source
La terminologie
backing field
est pleine de mystère. Le mot-clé utilisé estfield
. Lesget/set
méthodes suivent immédiatement à côté de la variable membre qui est sur le point d'être obtenue ou définie via ce mécanisme de méthodes de protection de porte. Lefield
mot clé fait simplement référence à la variable membre à définir ou à obtenir . À l'heure actuelle, Kotlin, vous ne pouvez pas faire référence à la variable membre directement dans les méthodes de porte de protection get ou set , car cela entraînera malheureusement une récursion infinie car elle réinvoquera le get ou le set et conduira ainsi le temps d'exécution dans l'abîme profond.En C # cependant, vous pouvez référencer directement la variable membre dans les méthodes getter / setter. Je cite cette comparaison pour présenter l'idée que ce
field
mot-clé est la façon dont le Kotlin actuel l'implémente, mais j'espère qu'il sera supprimé dans les versions ultérieures et nous permettra de référencer directement la variable membre directement sans entraîner de récursivité infinie.la source