Als Java-Entwickler ist mir das Konzept eines Hintergrundfeldes etwas fremd. Gegeben:
class Sample {
var counter = 0 // the initializer value is written directly to the backing field
set(value) {
if (value >= 0) field = value
}
}
Wofür ist dieses Hintergrundfeld gut? Kotlin-Dokumente sagten:
Klassen in Kotlin können keine Felder haben. Manchmal ist es jedoch erforderlich, ein Hintergrundfeld zu haben, wenn benutzerdefinierte Accessoren verwendet werden .
Warum? Was ist der Unterschied zur Verwendung des Eigenschaftsnamens selbst im Setter, z. B. *
class Sample {
var counter = 0
set(value) {
if (value >= 0) this.counter = value // or just counter = value?
}
}
android
kotlin
kotlin-android-extensions
Yudhistira Arya
quelle
quelle
this.counter = value
dies beim Lesen von Kotlins Dokumenten mit dem Java-Äquivalent identisch ist.Antworten:
Wenn Sie beispielsweise kein
field
Schlüsselwort haben, können Sie den Wert imget()
oder nicht tatsächlich festlegen / abrufenset(value)
. Sie können auf das Hintergrundfeld in den benutzerdefinierten Accessoren zugreifen.Dies ist der äquivalente Java-Code Ihres Beispiels:
Anscheinend ist dies nicht gut, da der Setter nur eine unendliche Rekursion in sich selbst ist und niemals etwas ändert. Denken Sie daran, dass in Kotlin jedes Mal, wenn Sie schreiben,
foo.bar = value
es in einen Setter-Aufruf anstelle von a übersetzt wirdPUTFIELD
.BEARBEITEN: Java hat Felder, während Kotlin Eigenschaften hat , was ein eher übergeordnetes Konzept als Felder ist.
Es gibt zwei Arten von Eigenschaften: eine mit Hintergrundfeld, eine ohne.
Eine Eigenschaft mit einem Hintergrundfeld speichert den Wert in Form eines Feldes. Dieses Feld ermöglicht das Speichern von Werten im Speicher. Ein Beispiel für eine solche Eigenschaft sind die
first
undsecond
Eigenschaften vonPair
. Diese Eigenschaft ändert die speicherinterne Darstellung vonPair
.Eine Eigenschaft ohne Hintergrundfeld muss ihren Wert auf andere Weise als direkt im Speicher speichern. Es muss aus anderen Eigenschaften oder dem Objekt selbst berechnet werden. Ein Beispiel für eine solche Eigenschaft ist die
indices
Erweiterungseigenschaft vonList
, die nicht durch ein Feld unterstützt wird, sondern ein auf dersize
Eigenschaft basierendes berechnetes Ergebnis . Daher wird die speicherinterne Darstellung von nicht geändertList
(was überhaupt nicht möglich ist, da Java statisch typisiert ist).quelle
this.counter = value
dies auch mit Java-Äquivalenten der Fall ist.field
eher ein Zeiger oder ein Verweis auf eine vorhandene Mitgliedsvariable ist? Da das alsoget/set
unmittelbar folgtcounter
, ist dasfield
Schlüsselwort ein Verweis aufcounter
. Richtig?Anfangs hatte auch ich Schwierigkeiten, dieses Konzept zu verstehen. Lassen Sie es mich Ihnen anhand eines Beispiels erklären.
Betrachten Sie diese Kotlin-Klasse
Wenn wir uns nun den Code ansehen, können wir sehen, dass er zwei Eigenschaften hat, nämlich -
size
(mit Standard-Accessoren) undisEmpty
(mit benutzerdefinierten Accessoren). Aber es hat nur 1 Feld dhsize
. Um zu verstehen, dass es nur ein Feld gibt, sehen wir uns das Java-Äquivalent dieser Klasse an.Gehen Sie zu Extras -> Kotlin -> Kotlin ByteCode in Android Studio anzeigen. Klicken Sie auf Dekompilieren.
Wir können deutlich sehen, dass die Java-Klasse nur Getter- und Setter-Funktionen für
isEmpty
hat und kein Feld dafür deklariert ist. Ebenso gibt es in Kotlin kein Hintergrundfeld für die EigenschaftisEmpty
, da die Eigenschaft überhaupt nicht von diesem Feld abhängt. Also kein Hintergrundfeld.Lassen Sie uns nun den benutzerdefinierten Getter und Setter der
isEmpty
Eigenschaft entfernen .Und das Java-Äquivalent der obigen Klasse ist
Hier sehen wir sowohl die Felder
size
als auchisEmpty
.isEmpty
ist ein Hintergrundfeld, da der Getter und der Setter für dieisEmpty
Eigenschaft davon abhängen.quelle
field
Schlüsselwort benötigt. Ist es möglich, dass eine Sprachverbesserung von Kotlin dieses seltsamefield
Schlüsselwort entfernt und verhindert, dass die hilflosen Seelen in den Abgrund einer unendlichen Rekursion fallen?Sicherungsfelder eignen sich zum Ausführen der Validierung oder zum Auslösen von Ereignissen bei Statusänderungen. Denken Sie an die Zeiten, in denen Sie einem Java-Setter / Getter Code hinzugefügt haben. Sicherungsfelder wären in ähnlichen Szenarien nützlich. Sie würden Hintergrundfelder verwenden, wenn Sie Setter / Getter steuern oder sichtbar machen müssen.
Wenn Sie dem Feld den Feldnamen selbst zuweisen, rufen Sie tatsächlich den Setter auf (dh
set(value)
). In dem Beispiel, das Sie haben,this.counter = value
würde in set (Wert) zurückkehren, bis wir unseren Stapel überlaufen. Mit wirdfield
der Setter- (oder Getter-) Code umgangen.quelle
field
ist nicht in C #, daher brauchen wir eine bessere Erklärung als die hier zitierte.Mein Verständnis ist , unter Verwendung von Feldkennung als Verweis auf den Wert der Eigenschaft in get oder set , wenn Sie ändern möchten oder den Wert der Eigenschaft in verwenden get oder set .
Beispielsweise:
Dann:
quelle
Die Terminologie
backing field
ist voller Geheimnisse. Das verwendete Schlüsselwort istfield
. Dieget/set
Methoden folgen unmittelbar neben der Elementvariablen, die über diesen Mechanismus für Türschutzmethoden abgerufen oder eingestellt werden soll. Dasfield
Schlüsselwort bezieht sich nur auf die Mitgliedsvariable, die gesetzt oder abgerufen werden soll . Derzeit Kotlin, können Sie nicht auf die Membervariable beziehen sich direkt in der get oder set Schutztür Methoden , weil es leider zu Endlosschleife führen wird , weil es wird wieder invoke der get oder Satz und damit LEDs Auf der Laufzeit nach unten in den tiefen Abgrund.In C # können Sie jedoch direkt auf die Elementvariable innerhalb der Getter / Setter-Methoden verweisen. Ich zitiere diesen Vergleich, um die Idee zu präsentieren, dass dieses
field
Schlüsselwort so ist, wie der gegenwärtige Kotlin es implementiert, aber ich hoffe, dass es in späteren Versionen entfernt wird und es uns ermöglicht, die Mitgliedsvariable direkt zu referenzieren, ohne dass es zu einer unendlichen Rekursion kommt.quelle