Extension property w Kotlin — co to jest, składnia i zastosowanie

Autor: IT Sectr Opublikowano: 2026-06-21 Czas czytania: 8 min

extension property — mechanizm Kotlin pozwalający dodawać nowe właściwości do istniejących klas bez dziedziczenia i bez zmiany kodu źródłowego. W przeciwieństwie do extension functions, właściwości-rozszerzenia nie mogą przechowywać stanu — są deklarowane tylko z getterem i opcjonalnie setterem, ponieważ nie mają backing field. Według Kotlin Documentation, 2025, extension properties są kompilowane do statycznych metod getter i setter z receiver jako pierwszym parametrem.

Najważniejsze

  • Extension property — właściwość z receiver type, dostępna przez składnię właściwości Kotlin
  • Brak backing field — extension property nie może przechowywać stanu, tylko obliczać
  • Getter obowiązkowy, setter opcjonalny — deklarowane jak zwykłe extension functions
  • Nullable-typy są obsługiwane: receiver może być nullable z wewnętrznym sprawdzeniem
  • Mutable extension property — tylko przy deklaracji var z getterem i setterem

Czym jest extension property w Kotlin?

extension property — to konstrukcja składniowa Kotlin, która dodaje właściwość do istniejącego typu bez zmiany jego deklaracji. Właściwość jest deklarowana z określeniem receiver-typu i obowiązkowo zawiera getter. Kluczowa różnica w porównaniu ze zwykłymi właściwościami — brak backing field: extension property nie może przechowywać danych, a jedynie oblicza je na podstawie receiver-obiektu.

Według Kotlin Foundation Survey (2024), extension properties są mniej popularne niż extension functions — regularnie używa ich około 45% programistów. Wynika to z ograniczenia braku stanu, co zawęża obszar zastosowań. Niemniej jednak, dla obliczanych właściwości logicznie powiązanych z typem, extension properties są najbardziej zwięzłą opcją.

Extension properties są kompilowane do pary statycznych metod getter i setter. Na poziomie kodu bajtowego nie ma różnicy między wywołaniem extension property a wywołaniem extension function — oba stają się statycznymi metodami z parametrem receiver. Według danych JetBrains (Kotlin Docs, 2025), narzut jest całkowicie nieobecny.

Używaj extension properties dla krótkich obliczanych wartości, które powinny wyglądać jak właściwości, a nie jak wywołania metod — poprawia to czytelność kodu i przestrzega zasady jednolitego dostępu.

Składnia extension property: val i var

Do deklaracji extension property używana jest składnia podobna do zwykłej właściwości, ale z prefiksem receiver-typu. val deklaruje read-only extension property z obowiązkowym getterem, var — mutable z getterem i opcjonalnym setterem.

kotlin
// Tylko do odczytu extension property
val String.isEmail: Boolean
    get() = this.contains("@") && this.contains(".")

// Wywołanie
val valid = "test@test.com".isEmail

Zwróć uwagę: extension property jest wywoływana bez nawiasów — str.isEmail, a nie str.isEmail(). To jest kluczowa różnica między extension property a extension function: property wygląda jak pole, choć w rzeczywistości jest obliczane przez getter.

Generic extension property

Extension properties mogą być uogólnione — receiver może używać parametrów generic. Pozwala to tworzyć uniwersalne właściwości działające z dowolnym typem kolekcji.

kotlin
val List<T>.secondOrNull: T?
    get() = if (size >= 2) this[1] else null

val items = listOf("a", "b", "c")
val second = items.secondOrNull // "b"

Właściwość secondOrNull działa dla dowolnego typu T, zwracając drugi element listy lub null, jeśli elementów jest mniej niż dwa. To typowy przykład, gdzie extension property jest bardziej odpowiednia niż funkcja — odwołanie wygląda jak odczyt pola.

Dlaczego extension property nie może przechowywać stanu

Extension property nie może mieć backing field, ponieważ nie jest dodawana do metadanych klasy — istnieje tylko jako para statycznych funkcji getter/setter. Backing field (słowo kluczowe field w Kotlin) to wewnętrzne pole klasy, które przechowuje wartość właściwości. Extension property nie ma dostępu do wewnętrznej struktury klasy.

kotlin
// ❌ BŁĄD: extension property nie może mieć pola zapasowego
var String.cachedValue: String
    get() = "computed"
    set(value) {
        field = value // pole nie jest dostępne!
    }

// ✅ POPRAWNIE: użyj zewnętrznego przechowywania
val cache = MutableMap<String, String>()

var String.cachedValue: String
    get() = cache[this] ?: ""
    set(value) { cache[this] = value }

Zewnętrzna Map w przykładzie rozwiązuje problem przechowywania, ale rodzi inny — wyciek pamięci. Wartości uzyskane przez extension property żyją w Map wiecznie, jeśli nie są czyszczone. To ograniczenie sprawia, że extension properties nie nadają się do buforowania lub przechowywania danych tymczasowych.

Do buforowania zaleca się używanie WeakHashMap lub mechanizmów z automatycznym czyszczeniem. JetBrains zaleca unikanie używania var extension properties z zewnętrznym magazynem w kodzie produkcyjnym bez starannego zarządzania cyklem życia.

Extension property vs extension function: kiedy co wybrać

Wybór między extension property a extension function zależy od semantyki: właściwość opisuje charakterystykę obiektu, a funkcja — działanie. Zasada jednolitego dostępu (Uniform Access Principle) mówi: klient nie powinien wiedzieć, czy wartość jest obliczana, czy przechowywana. Jeśli wartość można przedstawić jako cechę (długość, rozmiar, status) — użyj property.

KryteriumExtension propertyExtension function
WywołanieBez nawiasów: obj.propertyZ nawiasami: obj.function()
SemantykaCecha, atrybutDziałanie, operacja
Backing fieldNieobsługiwanyNie dotyczy
ParametryTylko getter/setterDowolne parametry
WydajnośćTaka sama (statyczna metoda)Taka sama (statyczna metoda)
Przykładtext.lengthtext.isEmail()

Zasada jest prosta: jeśli operacja przyjmuje parametry — użyj extension function. Jeśli to prosta obliczana wartość bez parametrów — extension property. Według danych Android Architecture Guide (Google, 2025), należy preferować extension properties do dostępu do danych i extension functions dla operacji z efektami ubocznymi.

Mutable extension property z var i setterem

Extension property ze słowem kluczowym var obsługuje setter, ale bez możliwości przechowywania wartości — setter zwykle wykonuje działanie uboczne lub zapisuje dane w zewnętrznym magazynie. Składnia jest analogiczna do mutable właściwości klas.

kotlin
// Mutable extension property z setterem
var StringBuilder.lastChar: Char
    get() = this[length - 1]
    set(value) {
        this.setCharAt(length - 1, value)
    }

val sb = StringBuilder("Kotlin")
println(sb.lastChar) // n
sb.lastChar = '!'
println(sb) // Kotli!

Właściwość lastChar — klasyczny przykład z dokumentacji Kotlin. Getter zwraca ostatni znak StringBuilder, setter zastępuje go nową wartością. Zwróć uwagę: stan jest przechowywany w samym StringBuilder (przez setCharAt), a nie w osobnym polu — to poprawne użycie extension property.

Praktyczne przykłady extension properties

W rzeczywistych projektach extension properties najczęściej są używane do upraszczania dostępu do danych kolekcji, obliczania rozmiarów lub statusów elementów UI oraz tworzenia wygodnego API na bazie istniejących klas. Biblioteka standardowa Kotlin aktywnie używa tego mechanizmu: size, indices, lastIndex dla kolekcji — to extension properties.

kotlin
// Extension properties dla kolekcji
val List<Int>.sumFast: Int
    get() = fold(0) { acc, i -> acc + i }

val String.half: String
    get() = this.substring(0, length / 2)

// Extension property dla Android View
val View.isVisible: Boolean
    get() = visibility == View.VISIBLE

// Sprawdzenie null przez bezpieczny odbiornik
val String?.isNullOrBlank: Boolean
    get() = this == null || this.isBlank()

Extension property isVisible dla View — przykład, który powinien znać każdy programista Android. Zamiast view.visibility == View.VISIBLE można pisać view.isVisible. To nie tylko krótsze, ale czyta się jak naturalny język: „jeśli widok jest widoczny”. Mimo prostoty, takie właściwości znacząco poprawiają czytelność kodu.

Często zadawane pytania

Czy można zadeklarować extension property dla companion object?

Nie, extension properties nie mogą być deklarowane dla companion object ani object declaration. Mechanizm extension ma zastosowanie tylko do klas, interfejsów i typów nullable. Dla object używaj zwykłych funkcji najwyższego poziomu.

Czym różni się extension property od inline-właściwości?

Inline-właściwość (z modyfikatorem inline) — mechanizm Kotlin do wywoływania gettera/settera bez tworzenia obiektu-właściwości. Extension property zawsze kompiluje się do statycznej metody, a inline-właściwość — do wywołania bez opakowania. Rozwiązują one różne zadania: extension property dodaje właściwość do istniejącego typu, inline — optymalizuje wywołania własnych właściwości.

Czy extension property obsługują adnotacje?

Tak, extension property może zawierać adnotacje, ale tylko na poziomie deklaracji. Nie można adnotować oddzielnie gettera lub settera extension property — w przeciwieństwie do zwykłych właściwości klasy. Przykład: @JvmName(„getIsValid”) val String.isValid get() = true.

Czy można użyć extension property z companion object klasy?

Nie, extension properties nie można zadeklarować z companion object jako receiver. To ograniczenie języka — extension property działa tylko z instancjami typów, a companion object to kontekst statyczny. Używaj extension functions najwyższego poziomu lub stałych.

Czy extension property wpływa na rozmiar APK?

Minimalnie. Każde extension property dodaje jedną statyczną metodę getter (i opcjonalnie setter) do skompilowanego kodu bajtowego. Dla porównania: utworzenie klasy-opakowującej z taką samą właściwością dodaje całą klasę. Extension properties — lżejsze podejście do rozszerzania funkcjonalności.

Podsumowanie

  • Extension property — obliczana właściwość dla istniejącego typu bez dziedziczenia
  • Brak backing field — stan nie jest przechowywany, tylko obliczany przez getter
  • var z setterem — możliwy, ale wymaga zewnętrznego magazynu do zapisu danych
  • Składnia — val/var z receiver-typem i obowiązkowym getterem
  • Wydajność — zerowy narzut, kompilowany do statycznej metody
  • Zastosowanie — obliczane cechy: długość, status, rozmiar, sprawdzenia
  • Ograniczenie — nie nadaje się do przechowywania stanu, buforowania bez zarządzania pamięcią

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również