In Kotlin kann eine Klasse einen primären Konstruktor und beliebig viele sekundäre Konstruktoren haben. Der Unterschied zu Java besteht darin, dass der primäre Konstruktor in der Kopfzeile der Klasse deklariert wird und Parameter und Modifikatoren enthalten kann. Sekundäre Konstruktoren müssen immer entweder einen anderen sekundären Konstruktor oder den primären Konstruktor oder den Konstruktor der Superklasse (mit dem Schlüsselwort super) aufrufen.
Wichtige Merkmale:
: super(...) aufrufen.super(...) oder einen anderen sekundären/primären Konstruktor aufgerufen.Beispiel für die Verwendung mit Vererbung:
open class A(val a: Int) { constructor(a: Int, str: String) : this(a) { println("Sekundär in A: $str") } } class B : A { constructor(a: Int) : super(a) { println("Sekundär in B") } constructor(a: Int, s: String) : super(a, s) { println("Sekundär #2 in B") } }
Was unterscheidet sich von dem Ansatz in Java:
Kann man in Kotlin eine abgeleitete Klasse erstellen, OHNE den Konstruktor der Superklasse explizit aufzurufen, wenn in der Basisklasse nur ein bestimmter Konstruktor vorhanden ist?
Antwort: Nein, im Gegensatz zu Java ist der Aufruf des Konstruktors der Superklasse in Kotlin obligatorisch und muss entweder im "Kopf" der Klasse oder nach dem Schlüsselwort : super() angegeben werden.
Beispiel für einen Fehler:
open class Base(val x: Int) class Derived : Base // Kompilierungsfehler!
Geschichte
In einem Mikrodienstprojekt wurde nach der Migration auf Kotlin das explizite Angabe des übergeordneten Konstruktors vergessen: Der Konstruktor der Superklasse mit einem erforderlichen Parameter wurde nicht aufgerufen, der Dienst konnte nicht kompiliert werden, es war erforderlich, die Signaturen zu refaktorisieren.
Geschichte
Ein Android-Projekt hatte eine tiefe Hierarchie (Activity → BaseActivity → CustomActivity), dem Hinzufügen eines sekundären Konstruktors gingen Parameter verloren, was dazu führte, dass der falsche Basiskonstruktor aufgerufen wurde und einige Felder null blieben - die Anwendung fiel zur Laufzeit mit NPE ab.
Geschichte
Im offenen Bibliothekscode umging ein sekundärer Konstruktor in der abgeleiteten Klasse versehentlich den primären Konstruktor, was zu zwei verschiedenen Initialisierungszweigen führte: manchmal war das Feld initialisiert, manchmal nicht. Der Fehler wurde erst nach langer Zeit anhand komplexer Bug-Berichte entdeckt.