Jako programista Java koncepcja pola zapasowego jest mi trochę obca. Dany:
class Sample {
var counter = 0 // the initializer value is written directly to the backing field
set(value) {
if (value >= 0) field = value
}
}
Do czego służy to pole zapasowe? Kotlin docs powiedział:
Zajęcia w Kotlinie nie mogą mieć pól. Czasami jednak konieczne jest posiadanie pola zapasowego podczas korzystania z niestandardowych akcesorów .
Czemu? Jaka jest różnica w używaniu samej nazwy właściwości wewnątrz settera, np. *
class Sample {
var counter = 0
set(value) {
if (value >= 0) this.counter = value // or just counter = value?
}
}
android
kotlin
kotlin-android-extensions
Yudhistira Arya
źródło
źródło
this.counter = value
tak samo jest z odpowiednikiem Java podczas czytania dokumentacji Kotlina.Odpowiedzi:
Ponieważ, powiedzmy, że nie masz
field
słowa kluczowego, nie będziesz w stanie ustawić / pobrać wartości wget()
lubset(value)
. Umożliwia dostęp do pola zapasowego w niestandardowych akcesoriach.Oto odpowiednik kodu Java Twojej próbki:
class Sample { private int counter = 0; public void setCounter(int value) { if (value >= 0) setCounter(value); } public int getCounter() { return counter; } }
Najwyraźniej nie jest to dobre, ponieważ seter jest po prostu nieskończoną rekurencją w sobie, niczego nie zmieniając. Pamiętaj, że w kotlin za każdym razem, gdy napiszesz
foo.bar = value
, zostanie to przetłumaczone na wywołanie ustawiające zamiastPUTFIELD
.EDYCJA: Java ma pola, a Kotlin ma właściwości , co jest pojęciem wyższego poziomu niż pola.
Istnieją dwa typy właściwości: jedna z polem zapasowym, druga bez.
Właściwość z polem zapasowym będzie przechowywać wartość w postaci pola. To pole umożliwia przechowywanie wartości w pamięci. Przykładem takiej właściwości są właściwości
first
i . Ta właściwość zmieni reprezentację w pamięci .second
Pair
Pair
Właściwość bez pola zapasowego będzie musiała przechowywać swoją wartość w inny sposób niż bezpośrednie przechowywanie jej w pamięci. Musi być obliczona na podstawie innych właściwości lub samego obiektu. Przykładem takiej właściwości jest właściwość
indices
rozszerzeniaList
, która nie jest obsługiwana przez pole, ale wynik obliczony na podstawiesize
właściwości. Więc nie zmieni reprezentacji w pamięciList
(czego nie może w ogóle zrobić, ponieważ Java jest wpisywana statycznie).źródło
this.counter = value
tak samo jest z odpowiednikiem w Javie.field
jest bardziej jak wskaźnik lub odniesienie do istniejącej zmiennej składowej. Ponieważ następujeget/set
bezpośrednio po nimcounter
,field
słowo kluczowe odnosi się docounter
. Dobrze?Na początku też ciężko było mi zrozumieć tę koncepcję. Pozwól, że wyjaśnię ci to na przykładzie.
Rozważ tę klasę Kotlin
class DummyClass { var size = 0; var isEmpty get() = size == 0 set(value) { size = size * 2 } }
Teraz, gdy spojrzymy na kod, widzimy, że ma 2 właściwości, tj. -
size
(z domyślnymi akcesoriami) iisEmpty
(z niestandardowymi akcesoriami). Ale ma tylko 1 pole tjsize
. Aby zrozumieć, że ma tylko 1 pole, zobaczmy odpowiednik tej klasy w Javie.Idź do Narzędzia -> Kotlin -> Pokaż Kotlin ByteCode w Android Studio. Kliknij Decompile.
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; } }
Wyraźnie widać, że klasa java ma tylko funkcje pobierające i ustawiające dla
isEmpty
i nie ma zadeklarowanego dla niej pola. Podobnie w Kotlinie nie ma pola zapasowego dla właściwościisEmpty
, ponieważ właściwość w ogóle nie zależy od tego pola. Zatem nie ma pola zapasowego.Teraz usuńmy niestandardowy pobierający i ustawiający
isEmpty
właściwość.class DummyClass { var size = 0; var isEmpty = false }
A odpowiednikiem Java powyższej klasy jest
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; } }
Tutaj widzimy zarówno pola, jak
size
iisEmpty
.isEmpty
jest polem zapasowym, ponieważ metoda pobierająca i ustawiającaisEmpty
właściwość zależy od niego.źródło
field
słowa kluczowego, czy jest możliwe, że ulepszenie języka Kotlin usunie to dziwnefield
słowo kluczowe i uniknie bezbronnych dusz wpadających w otchłań nieskończonej rekurencji?Pola zapasowe są dobre do przeprowadzania walidacji lub wyzwalania zdarzeń w przypadku zmiany stanu. Pomyśl o czasach, kiedy dodawałeś kod do settera / gettera Java. Pola zapasowe byłyby przydatne w podobnych scenariuszach. Używałbyś pól zapasowych, gdy trzeba kontrolować lub mieć wgląd w ustawiające / pobierające.
Kiedy przypisujesz pole z samą nazwą pola, w rzeczywistości wywołujesz metodę ustawiającą (tj
set(value)
.). W przykładzie, który masz,this.counter = value
będzie powtarzał się w set (wartość), dopóki nie przepełnimy naszego stosu. Użyciefield
omija kod ustawiający (lub pobierający).źródło
field
w języku C #, więc potrzebujemy lepszego wyjaśnienia niż to, które tu przytoczyłeś.Rozumiem, że identyfikator pola jest używany jako odniesienie do wartości właściwości w get lub set , gdy chcesz zmienić lub użyć wartości właściwości w get lub set .
Na przykład:
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} }
Następnie:
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)
źródło
Terminologia
backing field
jest pełna tajemnic. Użyte słowo kluczowe tofield
. Teget/set
metody, wynika bezpośrednio obok zmiennej składowej, która ma być uzyskać lub ustawić za pośrednictwem tej metody drzwi ochronne mechanizmu. Słowofield
kluczowe po prostu odnosi się do zmiennej składowej, która ma zostać ustawiona lub pobrana . Obecnie Kotlin nie można odwoływać się do zmiennej składowej bezpośrednio w metodach get lub set ochronnych drzwi, ponieważ niestety spowoduje to nieskończoną rekurencję, ponieważ ponownie wywoła get lub set, a tym samym doprowadzi środowisko wykonawcze w głęboką przepaść.Jednak w C # można bezpośrednio odwoływać się do zmiennej składowej wewnątrz metod pobierających / ustawiających. Cytuję to porównanie, aby przedstawić pomysł, że to
field
słowo kluczowe jest sposobem implementacji obecnego Kotlina, ale mam nadzieję, że zostanie ono usunięte w późniejszych wersjach i pozwoli nam bezpośrednio odwoływać się do zmiennej składowej bez powodowania nieskończonej rekurencji.źródło