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
| Modifikator | Sichtbar für |
|---|---|
public (Standard) | überall |
internal | im gleichen Modul |
protected | Klasse und Unterklassen |
private | nur 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 eigenemget/set - Klassen sind
final: für Vererbungopen, Überschreiben mitoverride abstract,internal,private setsteuern Struktur und Sichtbarkeitcompanion objectstattstatic,objectfür Singletonsrequire/checkprüfen Voraussetzungen
Aufgabe
Baue eine Klasse Rechteck mit berechneten Eigenschaften flaeche und umfang und vergleiche zwei Instanzen.