Klasy danych i klasy zapieczętowane
Proszę używać klas danych do porównywania wartości i metody copy(), a klas zapieczętowanych do tworzenia wyczerpujących hierarchii typów i przejrzystego modelowania stanów.
Klasy danych i klasy zapieczętowane to bezpłatna lekcja Android Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Android Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Android Academy zawiera 4 lekcji w sumie.
Czym są klasy danych?
Klasa danych w Kotlinie to klasa, której głównym zadaniem jest przechowywanie danych. Kompilator automatycznie generuje dla niej przydatne metody:
equals()— porównywanie dwóch instancji według wartościhashCode()— spójny skrót na podstawie właściwościtoString()— czytelna reprezentacja tekstowacopy()— tworzenie zmodyfikowanej kopii- Obsługa destrukturyzacji
Deklarowanie data class
Dodaj słowo kluczowe data przed class. Wszystkie właściwości muszą znajdować się w konstruktorze głównym:
data class User(val id: Int, val name: String, val email: String)
fun main() {
val u1 = User(1, "Alice", "alice@example.com")
val u2 = User(1, "Alice", "alice@example.com")
println(u1) // User(id=1, name=Alice, email=alice@example.com)
println(u1 == u2) // true (value equality)
println(u1 === u2) // false (different objects)
}copy() — modyfikowanie jednego pola
copy() tworzy nową instancję ze zmienionymi wybranymi właściwościami. Oryginał nie jest modyfikowany (niezmienność):
data class Product(val name: String, val price: Double, val inStock: Boolean)
fun main() {
val original = Product("Laptop", 999.0, true)
// Only change the price; keep everything else
val onSale = original.copy(price = 799.0)
println(original) // Product(name=Laptop, price=999.0, inStock=true)
println(onSale) // Product(name=Laptop, price=799.0, inStock=true)
}Deklaracje destrukturyzujące
Klasy danych obsługują destrukturyzację — można rozpakować właściwości do zmiennych za pomocą funkcji componentN() generowanych przez kompilator:
data class Point(val x: Int, val y: Int)
fun main() {
val point = Point(10, 20)
// Destructure into separate variables
val (x, y) = point
println("x=$x, y=$y") // x=10, y=20
// Also works in for loops with maps
val scores = mapOf("Alice" to 95, "Bob" to 88)
for ((name, score) in scores) {
println("$name: $score")
}
}Czym są klasy sealed?
Klasa sealed to ograniczona hierarchia klas — wszystkie podklasy muszą być zdefiniowane w tym samym pliku. Dzięki temu zbiór możliwych typów jest znany w czasie kompilacji.
Klasy sealed służą do reprezentowania skończonego zbioru stanów, takich jak wyniki operacji sieciowych, stany interfejsu użytkownika czy zdarzenia nawigacji.
Składnia klasy sealed
Podklasy można deklarować bezpośrednio wewnątrz klasy lub w tym samym pliku:
sealed class NetworkResult<out T> {
data class Success<T>(val data: T) : NetworkResult<T>()
data class Error(val message: String, val code: Int = 0) : NetworkResult<Nothing>()
object Loading : NetworkResult<Nothing>()
}
fun handle(result: NetworkResult<String>) {
when (result) {
is NetworkResult.Success -> println("Data: ${result.data}")
is NetworkResult.Error -> println("Error ${result.code}: ${result.message}")
NetworkResult.Loading -> println("Loading...")
}
}Klasa sealed + when (zupełne dopasowanie)
Na tym polega siła klas sealed: wyrażenie when jest wyczerpujące. Kompilator wymaga obsłużenia każdego podtypu — nie można pominąć żadnego przypadku:
sealed class UiState {
object Loading : UiState()
data class Success(val message: String) : UiState()
data class Error(val error: String) : UiState()
}
fun render(state: UiState): String = when (state) {
is UiState.Loading -> "Showing spinner"
is UiState.Success -> "Show: ${state.message}"
is UiState.Error -> "Error: ${state.error}"
// Compiler error if you remove any branch!
}
fun main() {
println(render(UiState.Loading))
println(render(UiState.Success("Loaded!")))
}Klasa sealed a enum
Oba rozwiązania reprezentują stały zbiór wartości, ale:
- Enum — każda stała jest pojedynczą instancją, bez dodatkowych danych dla wariantu
- Klasa sealed — każdy wariant może przechowywać inne dane oraz być klasą lub obiektem
Proszę używać enum, gdy warianty nie wymagają danych. Klasa sealed sprawdzi się, gdy warianty potrzebują różnych właściwości.
Deklaracje object (singletony)
object tworzy singleton — jedną instancję, tworzona leniwie i bezpiecznie w środowisku wielowątkowym:
object AppConfig {
const val BASE_URL = "https://api.example.com"
const val TIMEOUT = 30L
fun buildUrl(path: String) = "$BASE_URL/$path"
}
fun main() {
println(AppConfig.BASE_URL) // https://api.example.com
println(AppConfig.buildUrl("users")) // https://api.example.com/users
}Obiekty towarzyszące
Obiekt towarzyszący znajduje się wewnątrz klasy i udostępnia elementy na poziomie klasy (podobnie jak static w języku Java). Jest często używany do tworzenia metod fabrykujących:
class Token private constructor(val value: String) {
companion object {
fun create(raw: String): Token {
val cleaned = raw.trim()
require(cleaned.isNotEmpty()) { "Token must not be blank" }
return Token(cleaned)
}
}
}
fun main() {
val token = Token.create(" abc123 ")
println(token.value) // abc123
}Klasy danych w rzeczywistej aplikacji
Połącz klasy danych z klasami sealed, aby w przejrzysty sposób modelować stany:
data class Post(val id: Int, val title: String, val body: String)
sealed class PostState {
object Loading : PostState()
data class Loaded(val posts: List<Post>) : PostState()
data class Failed(val reason: String) : PostState()
}
fun showState(state: PostState) = when (state) {
PostState.Loading -> println("Fetching posts...")
is PostState.Loaded -> println("${state.posts.size} posts loaded")
is PostState.Failed -> println("Failed: ${state.reason}")
}
fun main() {
showState(PostState.Loaded(listOf(
Post(1, "Hello", "World"),
Post(2, "Kotlin", "Rocks")
)))
}Szybki test
Które stwierdzenie najlepiej opisuje różnicę między klasami sealed a zwykłymi klasami abstrakcyjnymi?
Podsumowanie: klasy danych i sealed
Ma Pan/Pani teraz do dyspozycji dwa potężne narzędzia języka Kotlin:
- data class — równość oparta na wartościach,
copy(), destrukturyzacja, automatycznie generowanetoString() - sealed class — skończona hierarchia typów, wyczerpujące
when, każdy wariant może przechowywać własne dane - object — singleton, obiekty towarzyszące do metod fabrykujących
Razem wzorce te zastępują rozwlekły kod w języku Java i umożliwiają przejrzyste oraz bezpieczne modelowanie stanów.
Często zadawane pytania
Czy lekcja „Klasy danych i klasy zapieczętowane” jest bezpłatna?
Tak — pełny tekst „Klasy danych i klasy zapieczętowane” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Android Academy, przejdź na CoddyKit PRO. Kurs Android Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Klasy danych i klasy zapieczętowane”?
Proszę używać klas danych do porównywania wartości i metody copy(), a klas zapieczętowanych do tworzenia wyczerpujących hierarchii typów i przejrzystego modelowania stanów. Ćwiczysz Android Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Android Academy?
Nie wymagamy żadnego doświadczenia. Android Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Klasy danych i klasy zapieczętowane”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Android Academy?
Tak. Każda lekcja Android Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Bezpieczeństwo wartości null
- Klasy i obiekty
- Klasy danych i klasy zapieczętowane
- Funkcje rozszerzające i funkcje wyższego rzędu