ProgrammierungKotlin/Java Entwickler

Wie funktioniert die Vererbung von Konstruktoren in Kotlin, wie funktioniert der Aufruf des Superkonstruktors, und welche Fallstricke gibt es bei der Kombination von primären und sekundären Konstruktoren? Geben Sie Beispiele für verschiedene Fälle und erklären Sie den Unterschied zu Java.

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort

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:

  • Wenn die Superklasse einen primären Konstruktor mit erforderlichen Parametern hat, muss die abgeleitete Klasse diesen immer explizit über : super(...) aufrufen.
  • Im sekundären Konstruktor wird die Basisklasse entweder über super(...) oder einen anderen sekundären/primären Konstruktor aufgerufen.
  • Es ist kein Konflikt bei der Initialisierung zulässig: Alle Felder müssen immer korrekt initialisiert werden.

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:

  • In Kotlin kann der Konstruktor der Superklasse NICHT ausgelassen werden.
  • Der primäre Konstruktor initialisiert immer die Basiseigenschaften und kann implizit sein.

Fangfrage

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!

Beispiele für reale Fehler aufgrund mangelnden Wissens über die Feinheiten des Themas


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.