Kurz: Für Klassen, die vor allem Daten halten, erzeugt der Compiler equals, hashCode, toString, copy und Destrukturierung:
Teil des Kurses Kotlin
Data Classes
Für Klassen, die vor allem Daten halten, erzeugt der Compiler equals, hashCode, toString, copy und Destrukturierung:
data class Person(val name: String, val alter: Int, val ort: String = "unbekannt")
fun main() {
val a = Person("Mia", 17)
val b = Person("Mia", 17)
println(a)
println(a == b) // Inhaltsvergleich
println(a === b) // Identität
val c = a.copy(alter = 18, ort = "Berlin")
println(c)
val (name, alter) = c // Destrukturierung
println("$name ist $alter")
println(setOf(a, b).size)
println(a.hashCode() == b.hashCode())
}Ausgabe:
Person(name=Mia, alter=17, ort=unbekannt)
true
false
Person(name=Mia, alter=18, ort=Berlin)
Mia ist 18
1
trueDer Vergleich mit == ruft equals auf (Inhalt). Das ist anders als in Java, wo == Referenzen vergleicht.
Enums
enum class Richtung(val dx: Int, val dy: Int) {
NORD(0, -1), OST(1, 0), SUED(0, 1), WEST(-1, 0);
fun drehe(): Richtung = values()[(ordinal + 1) % values().size]
}
enum class Status { OFFEN, ERLEDIGT }
fun text(s: Status) = when (s) {
Status.OFFEN -> "noch zu tun"
Status.ERLEDIGT -> "fertig"
}
fun main() {
println(Richtung.NORD.drehe())
println(Richtung.WEST.drehe())
println(Richtung.valueOf("SUED").dx)
println(Richtung.values().map { it.name })
println(text(Status.OFFEN))
}Ausgabe:
OST
NORD
0
[NORD, OST, SUED, WEST]
noch zu tunSealed Classes: geschlossene Hierarchien
Eine versiegelte Klasse hat eine feste, dem Compiler bekannte Menge von Unterklassen. Dadurch muss when alle Fälle abdecken, ohne else:
sealed class Ergebnis {
data class Erfolg(val wert: Int) : Ergebnis()
data class Fehler(val grund: String) : Ergebnis()
object Laden : Ergebnis()
}
fun zeige(e: Ergebnis): String = when (e) {
is Ergebnis.Erfolg -> "Wert: ${e.wert}"
is Ergebnis.Fehler -> "Fehler: ${e.grund}"
Ergebnis.Laden -> "lädt ..."
}
fun teile(a: Int, b: Int): Ergebnis =
if (b == 0) Ergebnis.Fehler("Division durch null") else Ergebnis.Erfolg(a / b)
fun main() {
println(zeige(teile(10, 2)))
println(zeige(teile(1, 0)))
println(zeige(Ergebnis.Laden))
}Ausgabe:
Wert: 5
Fehler: Division durch null
lädt ...Sealed Classes sind ideal für Zustände (Laden/Erfolg/Fehler in Android-Apps), Ausdrucksbäume und Nachrichtentypen.
Ausdrucksbaum
sealed class Ausdruck
data class Zahl(val n: Double) : Ausdruck()
data class Summe(val l: Ausdruck, val r: Ausdruck) : Ausdruck()
data class Produkt(val l: Ausdruck, val r: Ausdruck) : Ausdruck()
fun auswerten(a: Ausdruck): Double = when (a) {
is Zahl -> a.n
is Summe -> auswerten(a.l) + auswerten(a.r)
is Produkt -> auswerten(a.l) * auswerten(a.r)
}
fun main() {
val ausdruck = Produkt(Summe(Zahl(2.0), Zahl(3.0)), Zahl(4.0))
println(auswerten(ausdruck))
println(ausdruck)
}Ausgabe:
20.0
Produkt(l=Summe(l=Zahl(n=2.0), r=Zahl(n=3.0)), r=Zahl(n=4.0))Typaliase und Pair/Triple
typealias Namen = List<String>
typealias Handler = (String) -> Unit
fun begruesse(n: Namen, h: Handler) = n.forEach(h)
fun main() {
begruesse(listOf("Mia", "Tom")) { println("Hallo $it") }
val p = "a" to 1 // Pair
val t = Triple("x", 2, true)
println("$p ${p.first} ${t.third} ${t.toList()}")
}Ausgabe:
Hallo Mia
Hallo Tom
(a, 1) a true [x, 2, true]Merke
data class:equals,toString,copy, Destrukturierung inklusiveenum classmit Eigenschaften und Methoden;values(),valueOf()sealed class+whenohneelse: Der Compiler prüft die Vollständigkeit==vergleicht Inhalte,===Referenzentypealiasfür lesbare Typnamen
Übungsaufgabe
Modelliere Zahlungsarten (Bar, Karte mit Nummer, PayPal mit E-Mail) als Sealed Class und gib für jede eine Beschreibung aus.
Quiz zur Selbstkontrolle
Was erzeugt eine data class automatisch?
- equals, hashCode, toString, copy (richtig)
- Nur Getter
- Eine Datenbank
- Threads
Warum sind Sealed Classes nützlich?
- when muss alle Fälle abdecken, ohne else (richtig)
- Sie sind schneller
- Sie sind privat
- Sie ersetzen Strings
Was macht copy()?
- Kopiert das Objekt mit einzelnen geänderten Werten (richtig)
- Löscht das Objekt
- Vergleicht Objekte
- Serialisiert
Weiter im Kurs
Zurück: Klassen und Objekte
Weiter: Interfaces, Generics und Delegation
Alle Kapitel: Kotlin im Überblick