EMZETT.
Login

Kurz: Der primäre Konstruktor steht direkt im Klassenkopf. Mit val/var werden Parameter zu Eigenschaften. Klassen sind standardmäßig final (nicht vererbbar), Sichtbarkeit standardmäßig public.

Teil des Kurses Kotlin

Kapitel 7 von 13 im Kurs Kotlin (Abschnitt „Objektorientierung“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Klassen

Der primäre Konstruktor steht direkt im Klassenkopf. Mit val/var werden Parameter zu Eigenschaften. Klassen sind standardmäßig final (nicht vererbbar), Sichtbarkeit standardmäßig public.

class Konto(val inhaber: String, startStand: Double = 0.0) {
    var stand: Double = startStand
        private set                         // nur innerhalb der Klasse änderbar
 
    val reich: Boolean
        get() = stand > 1000                // berechnete Eigenschaft
 
    init {
        println("Konto für $inhaber angelegt")
    }
 
    fun einzahlen(betrag: Double) {
        require(betrag > 0) { "Betrag muss positiv sein" }     // Voraussetzung prüfen
        stand += betrag
    }
 
    override fun toString() = "$inhaber: ${"%.2f".format(stand)}"
}
 
fun main() {
    val k = Konto("Mia", 100.0)
    k.einzahlen(50.0)
    println(k)
    println(k.reich)
    try {
        k.einzahlen(-5.0)
    } catch (e: IllegalArgumentException) {
        println("Fehler: ${e.message}")
    }
    // k.stand = 5.0     // Fehler: private set
}

Ausgabe:

Konto für Mia angelegt
Mia: 150.00
false
Fehler: Betrag muss positiv sein

Kein new: Objekte erzeugst du wie einen Funktionsaufruf, Konto("Mia").

Sekundäre Konstruktoren

class Punkt(val x: Int, val y: Int) {
    constructor() : this(0, 0)
    constructor(wert: Int) : this(wert, wert)
    fun abstandZumUrsprung() = Math.sqrt((x * x + y * y).toDouble())
}
 
fun main() {
    println(Punkt().abstandZumUrsprung())
    println(Punkt(3, 4).abstandZumUrsprung())
    println(Punkt(2).x)
}

Ausgabe:

0.0
5.0
2

Meistens ersetzen Standardwerte im primären Konstruktor sekundäre Konstruktoren.

Vererbung

Zum Vererben markierst du Klasse und Methoden mit open; überschreiben brauchst du override.

open class Tier(val name: String) {
    open fun laut() = "..."
    fun vorstellen() = "$name sagt ${laut()}"
}
 
class Hund(name: String) : Tier(name) {
    override fun laut() = "Wuff"
}
 
class Katze(name: String, val leben: Int = 9) : Tier(name) {
    override fun laut() = "Miau"
}
 
abstract class Form {
    abstract fun flaeche(): Double
    fun beschreibung() = "${this::class.java.simpleName} mit Fläche ${"%.2f".format(flaeche())}"
}
 
class Kreis(val r: Double) : Form() { override fun flaeche() = Math.PI * r * r }
class Rechteck(val b: Double, val h: Double) : Form() { override fun flaeche() = b * h }
 
fun main() {
    val tiere = listOf(Hund("Rex"), Katze("Mimi"))
    for (t in tiere) println(t.vorstellen())
    println(tiere[1] is Katze)
    for (f in listOf(Kreis(1.0), Rechteck(2.0, 3.0))) println(f.beschreibung())
}

Ausgabe:

Rex sagt Wuff
Mimi sagt Miau
true
Kreis mit Fläche 3.14
Rechteck mit Fläche 6.00

Sichtbarkeit

ModifikatorSichtbar für
public (Standard)überall
internalim gleichen Modul
protectedKlasse und Unterklassen
privatenur in der Klasse bzw. Datei

Companion Object und Singleton

Kotlin hat keine static-Member. Stattdessen:

class Benutzer private constructor(val name: String) {
    companion object {
        const val MAX = 3
        private var anzahl = 0
        fun erstelle(name: String): Benutzer {
            anzahl++
            return Benutzer(name.capitalize())
        }
        fun anzahl() = anzahl
    }
}
 
object Konfiguration {                       // Singleton: genau eine Instanz
    var debug = false
    val version = "1.0"
    fun info() = "v$version, debug=$debug"
}
 
fun main() {
    val b = Benutzer.erstelle("mia")
    Benutzer.erstelle("tom")
    println("${b.name} ${Benutzer.anzahl()} ${Benutzer.MAX}")
    Konfiguration.debug = true
    println(Konfiguration.info())
 
    val ad = object {                         // anonymes Objekt
        val x = 10
        fun doppelt() = x * 2
    }
    println(ad.doppelt())
}

Ausgabe:

Mia 2 3
v1.0, debug=true
20

Verschachtelte und innere Klassen

class Aussen(val wert: Int) {
    class Verschachtelt { fun f() = "kennt Aussen nicht" }
    inner class Innen { fun f() = "kennt Aussen: $wert" }
}
 
fun main() {
    println(Aussen.Verschachtelt().f())
    println(Aussen(42).Innen().f())
}

Ausgabe:

kennt Aussen nicht
kennt Aussen: 42

Merke

  • Primärer Konstruktor im Klassenkopf, init-Blöcke, Eigenschaften mit eigenem get/set
  • Klassen sind final: für Vererbung open, Überschreiben mit override
  • abstract, internal, private set steuern Struktur und Sichtbarkeit
  • companion object statt static, object für Singletons
  • require/check prüfen Voraussetzungen

Übungsaufgabe

Baue eine Klasse Rechteck mit berechneten Eigenschaften flaeche und umfang und vergleiche zwei Instanzen.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Listen, Sets, Maps und Collection-Funktionen

Weiter: Data Classes, Sealed Classes und Enums

Alle Kapitel: Kotlin im Überblick