EMZETT.
Login

Kurz: interface Laufend { fun laeuft() = “läuft” }

Teil des Kurses Kotlin

Kapitel 9 von 13 im Kurs Kotlin. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Interfaces

interface Sprechend {
    val name: String                              // abstrakte Eigenschaft
    fun spricht(): String
    fun vorstellen() = "$name: ${spricht()}"      // Standardimplementierung
}
 
interface Laufend { fun laeuft() = "läuft" }
 
class Mensch(override val name: String) : Sprechend, Laufend {
    override fun spricht() = "Hallo"
}
 
class Roboter : Sprechend {
    override val name = "R2"
    override fun spricht() = "Piep"
}
 
fun main() {
    val liste: List<Sprechend> = listOf(Mensch("Mia"), Roboter())
    liste.forEach { println(it.vorstellen()) }
    println(Mensch("Tom").laeuft())
}

Ausgabe:

Mia: Hallo
R2: Piep
läuft

Anders als in Java dürfen Interfaces Eigenschaften und Standardmethoden haben. Eine Klasse kann mehrere Interfaces, aber nur eine Oberklasse haben.

Generics

class Kiste<T>(private val inhalt: T) {
    fun auspacken(): T = inhalt
}
 
fun <T> mitte(liste: List<T>): T = liste[liste.size / 2]
 
fun <T : Comparable<T>> groesstes(liste: List<T>): T {       // obere Schranke
    var m = liste.first()
    for (x in liste) if (x > m) m = x
    return m
}
 
class Stapel<T> {
    private val daten = mutableListOf<T>()
    fun push(x: T) { daten.add(x) }
    fun pop(): T? = if (daten.isEmpty()) null else daten.removeAt(daten.size - 1)
    val groesse get() = daten.size
}
 
fun main() {
    println(Kiste("Text").auspacken())
    println(Kiste(42).auspacken() + 1)
    println(mitte(listOf(1, 2, 3, 4, 5)))
    println(groesstes(listOf(3, 9, 4)))
    println(groesstes(listOf("kiwi", "apfel")))
    val s = Stapel<Int>()
    s.push(1); s.push(2)
    println("${s.pop()} ${s.pop()} ${s.pop()} ${s.groesse}")
}

Ausgabe:

Text
43
3
9
kiwi
2 1 null 0

Varianz: out und in

List<out T> ist kovariant: Eine List<String> darf als List<Any> verwendet werden (nur lesen). in ist kontravariant (nur schreiben). Das ist Kotlins sichere Variante der Java-Wildcards:

interface Quelle<out T> { fun hole(): T }
interface Senke<in T> { fun nimm(x: T) }
 
fun main() {
    val strings: List<String> = listOf("a")
    val anys: List<Any> = strings                // erlaubt wegen "out"
    println(anys)
    val quelle = object : Quelle<String> { override fun hole() = "daten" }
    val q: Quelle<Any> = quelle
    println(q.hole())
    val senke = object : Senke<Any> { override fun nimm(x: Any) = println("nehme $x") }
    val s: Senke<String> = senke
    s.nimm("Text")
}

Ausgabe:

[a]
daten
nehme Text

Delegation

Klassendelegation mit by

interface Drucker { fun drucke(text: String) }
class KonsolenDrucker : Drucker { override fun drucke(text: String) = println("> $text") }
 
class Bericht(drucker: Drucker) : Drucker by drucker {      // delegiert alle Methoden
    fun fertig() = drucke("Bericht fertig")
}
 
fun main() {
    Bericht(KonsolenDrucker()).fertig()
}

Ausgabe:

> Bericht fertig

Eigenschaften-Delegation

import kotlin.properties.Delegates
 
class Einstellung {
    var lautstaerke: Int by Delegates.observable(5) { _, alt, neu ->
        println("Lautstärke: $alt -> $neu")
    }
    var name: String by Delegates.vetoable("x") { _, _, neu -> neu.length <= 5 }
    val teuer: Int by lazy { println("berechne"); 42 }
}
 
fun main() {
    val e = Einstellung()
    e.lautstaerke = 8
    e.name = "kurz"
    e.name = "viel zu lang"
    println(e.name)
    println(e.teuer + e.teuer)
}

Ausgabe:

Lautstärke: 5 -> 8
kurz
berechne
84

Merke

  • Interfaces mit Eigenschaften und Standardmethoden, mehrere pro Klasse
  • Generics <T>, Schranken <T : Comparable<T>>, Varianz out/in
  • Klassendelegation mit by statt Vererbung
  • Delegates.observable, vetoable und lazy für Eigenschaften

Übungsaufgabe

Schreibe eine generische Klasse Paar<A, B> mit Funktion tauschen(), die Paar<B, A> liefert.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Data Classes, Sealed Classes und Enums

Weiter: Scope-Funktionen, DSLs und Idiome

Alle Kapitel: Kotlin im Überblick