sealed class i sealed interface w Kotlin to mechanizmy ograniczonej hierarchii typów, gdzie wszystkie możliwe podklasy są znane na etapie kompilacji. W przeciwieństwie do zwykłych klas abstrakcyjnych, sealed class gwarantuje wyczerpującą obsługę wszystkich wariantów w wyrażeniu when. Zgodnie z dokumentacją JetBrains Kotlin Language Guide (2026), typy sealed stanowią podstawę modelowania stanów, ekranów UI i typów wynikowych w projektach Kotlin.
Najważniejsze
sealed class to klasa abstrakcyjna z ograniczeniem: wszystkie jej bezpośrednie podklasy muszą być zadeklarowane w tym samym pliku co sealed class. To ograniczenie sprawia, że hierarchia jest zamknięta (sealed) — żaden kod poza plikiem nie może dodać nowej podklasy.
sealed interface, dodany w Kotlin 1.5, zapewnia tę samą gwarancję, ale z elastycznością interfejsu: sealed interface może być zaimplementowany przez wiele klas, obiektów lub innych interfejsów w jednym pliku. W przeciwieństwie do sealed class, sealed interface nie ma ograniczenia pojedynczego dziedziczenia — klasa może implementować wiele sealed interfejsów jednocześnie.
Według Kotlin Evolution and Roadmap (2026), sealed interface został dodany na prośbę społeczności w celu bardziej elastycznego modelowania. Główną motywacją była możliwość łączenia niezależnych hierarchii typów bez wielodziedziczenia klas.
Deklaracja sealed class zaczyna się od modyfikatora sealed przed class. Podklasy są deklarowane w tym samym pliku.
sealed class NetworkResult {
data class Success(val data: String) : NetworkResult()
data class Error(val message: String) : NetworkResult()
object Loading : NetworkResult()
}
Każda podklasa sealed class może mieć własne właściwości i metody. Loading to singleton (object), Success i Error to data class z parametrami. Kompilator zna wszystkie trzy warianty i sprawdza ich kompletność przy użyciu w when.
sealed klasy mogą być zagnieżdżone, tworząc wielopoziomowe hierarchie dla złożonych modeli danych bez utraty bezpieczeństwa typów.
sealed class UiState {
object Idle : UiState()
object Loading : UiState()
data class Content(val items: List<Item>) : UiState()
data class Error(val exception: Throwable) : UiState()
}
sealed interface jest deklarowany podobnie do sealed class, ale pozwala na implementację wielu sealed interfejsów w jednej klasie.
sealed interface Action
sealed interface Loggable
data class Navigate(val route: String) : Action, Loggable
data class ShowToast(val text: String) : Action
object GoBack : Action, Loggable
Klasa Navigate implementuje jednocześnie dwa sealed interfejsy — Action i Loggable. Dla sealed class jest to niemożliwe ze względu na ograniczenie pojedynczego dziedziczenia. sealed interface daje elastyczność łączenia niezależnych hierarchii.
sealed interface jest preferowany, gdy hierarchia nie wymaga wspólnego stanu ani konstruktora. Zgodnie z JetBrains Kotlin Guidelines (2026), sealed interface powinien być używany domyślnie dla wszystkich nowych hierarchii, gdzie nie jest potrzebny wspólny konstruktor, co czyni kod bardziej elastycznym na przyszłe rozszerzenia.
Główną zaletą typów sealed jest wyczerpująca (exhaustive) obsługa w wyrażeniu when. Kompilator sprawdza, czy wszystkie możliwe podklasy zostały uwzględnione.
fun handleResult(result: NetworkResult): String = when (result) {
is NetworkResult.Success -> "Data: ${result.data}"
is NetworkResult.Error -> "Error: ${result.message}"
is NetworkResult.Loading -> "Loading..."
// else nie jest wymagane — kompilator wie, że wszystkie warianty są obsłużone
}
Jeśli programista doda nową podklasę w sealed hierarchii, ale zapomni obsłużyć ją w when — kompilator zgłosi błąd. To bezpieczeństwo na poziomie typów, niedostępne przy użyciu otwartych hierarchii z gałęzią else.
Według Google Android Developers (2026), sealed klasy to zalecany sposób modelowania stanu UI w Jetpack Compose. Wyczerpująca kontrola when zapobiega sytuacjom, w których programista obsłużył nie wszystkie możliwe warianty wyświetlania ekranu.
enum class i sealed class są często mylone, ale mają różne przeznaczenie i możliwości.
| Cechy | sealed class | enum class |
|---|---|---|
| Instancje | Wiele (data class), jedna (object) | Dokładnie jedna na stałą |
| Właściwości | Różne dla każdej podklasy | Identyczne dla wszystkich stałych |
| Dziedziczenie | Tak (od sealed class) | Nie (implicit final) |
| Konstruktor | Może mieć parametry | Tylko wspólny dla wszystkich stałych |
| Hierarchia | Ograniczona, sealed | Stały zestaw stałych |
Wybór między sealed class a enum class zależy od zadania. Jeśli warianty nie niosą dodatkowych danych — użyj enum. Jeśli każdy wariant zawiera unikalne pola — użyj sealed class lub sealed interface.
sealed typy są używane w projektach Kotlin do wielu standardowych scenariuszy wymagających modelowania z bezpieczeństwem typów.
Każdy ekran Compose może mieć sealed class UiState, która opisuje wszystkie możliwe stany: Idle, Loading, Content(data), Error(exception). Wyrażenie when gwarantuje, że wszystkie stany są obsłużone.
NetworkResult z wariantami Success, Error, Loading to standardowy wzorzec w projektach Kotlin z Retrofit i Ktor. sealed class zapewnia bezpieczną obsługę każdego wyniku zapytania.
sealed interface dla tras nawigacji pozwala modułom deklarować własne trasy, pozostając w ramach jednej hierarchii. Eliminuje to błędy z nieznanymi trasami na etapie kompilacji.
Według KotlinConf (2025), sealed class i sealed interface stanowią podstawę type-safe projektowania w nowoczesnych aplikacjach Kotlin. Łączy się je z data class do modelowania złożonych struktur domenowych bez utraty bezpieczeństwa na etapie kompilacji.
Często zadawane pytania
Wszystkie bezpośrednie podklasy sealed class muszą być zadeklarowane w tym samym pliku. Dla sealed interface obowiązuje ta sama zasada — implementacje w jednym pliku.
Nie, zasada jednego pliku obowiązuje również dla sealed interface. Wszystkie implementacje muszą znajdować się w pliku, w którym zadeklarowano sealed interface.
sealed interface nie ma stanu ani konstruktora, dopuszcza wielokrotną implementację. sealed class może mieć konstruktor i wspólny stan, ale klasa może dziedziczyć tylko jeden sealed class.
Kompilator sprawdza kompletność when: jeśli nie wszystkie podklasy są obsłużone, kod się nie kompiluje. Eliminuje to błędy runtime i czyni kod bezpieczniejszym.
Tak, sealed class może mieć konstruktor (domyślnie private). Wszystkie podklasy mogą przekazywać parametry do tego konstruktora przez super().
Podsumowanie
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.
Przeczytaj również