Właściwości rozszerzeń — to rozszerzenia dla klas, które pozwalają dodać gettery i settery bez możliwości dodania stanu (backing field). W Javie nie ma takiej możliwości, a odpowiednikiem jest pisanie metod pomocniczych. Historycznie, w celu dodania funkcjonalności używano metod statycznych lub obiektów opakowujących.
Problem: w zewnętrznych klasach często brakuje potrzebnych właściwości. Chcemy rozszerzyć klasę w sposób zwięzły i bezpieczny, nie naruszając enkapsulacji.
Rozwiązanie: w Kotlinie można zadeklarować właściwość rozszerzenia, która wygląda jak zwykła właściwość, ale jest zaimplementowana w postaci funkcji. Umożliwia to rozszerzenie typów, do których nie mamy dostępu do kodu źródłowego, w wygodny sposób.
Przykład kodu:
val String.firstChar: Char get() = this[0] println("Kotlin".firstChar) // K
Kluczowe cechy:
Czy można dodać backing field (stan) do właściwości rozszerzenia?
Nie, właściwość rozszerzenia tylko oblicza wartość na bieżąco i nie może przechowywać stanu.
Czy właściwości rozszerzeń mogą nadpisywać właściwości w klasach dziedziczących?
Nie, właściwości rozszerzeń (jak i funkcje rozszerzeń) są zasadniczo statyczne: nie mogą być nadpisywane ani wirtualne.
Jak kompilowana jest właściwość rozszerzenia i dlaczego nie jest syntaktycznym odpowiednikiem zwykłej właściwości?
Właściwość rozszerzenia tak naprawdę kompiluje się do statycznego gettera (i/lub settera) funkcji. Nie są one zawarte w encjach klasy i są widoczne tylko w kontekście pliku, w którym są zadeklarowane.
Negatywny przypadek
Programista próbował dodać właściwość rozszerzenia do przechowywania stanu "odwiedzono" w standardowych widokach Android:
var View.isVisited: Boolean get() = ... set(value) { ... } // Błąd: brak przechowywania
Zalety:
Wady:
Pozytywny przypadek
Zrealizowano właściwość rozszerzenia dla String w celu uzyskania rozszerzonego formatu:
val String.asTitle: String get() = this.replaceFirstChar { it.uppercase() }
Zalety:
Wady: