In Kotlin, una classe può avere un costruttore primario e quanti più costruttori secondari possibile. La differenza rispetto a Java è che in Kotlin il costruttore primario è dichiarato nell'intestazione della classe e può contenere parametri e modificatori. I costruttori secondari devono sempre chiamare un altro costruttore secondario, il costruttore primario o il costruttore della superclasse (tramite la parola chiave super).
Caratteristiche chiave:
: super(...).super(...) o un altro costruttore secondario/primario.Esempio di utilizzo con ereditarietà:
open class A(val a: Int) { constructor(a: Int, str: String) : this(a) { println("Secondario in A: $str") } } class B : A { constructor(a: Int) : super(a) { println("Secondario in B") } constructor(a: Int, s: String) : super(a, s) { println("Secondario #2 in B") } }
In cosa differisce l'approccio da Java:
È possibile in Kotlin creare una classe derivata SENZA chiamare esplicitamente il costruttore della superclasse, se nella classe base è presente solo un certo costruttore?
Risposta: No, a differenza di Java, in Kotlin la chiamata al costruttore della superclasse è obbligatoria e deve essere specificata esplicitamente sia nell'intestazione della classe che dopo la parola chiave : super().
Esempio di errore:
open class Base(val x: Int) class Derived : Base // Errore di compilazione!
Storia
In un progetto microservizi dopo la migrazione a Kotlin, si è dimenticato di specificare esplicitamente il costruttore genitore: il costruttore della superclasse con un parametro obbligatorio non veniva chiamato, il servizio non si compilava e è stato necessario rifattorizzare le firme.
Storia
Un progetto Android aveva una profonda gerarchia (Activity → BaseActivity → CustomActivity), l'aggiunta di un costruttore secondario perdeva parametri, di conseguenza veniva chiamato il costruttore di base sbagliato e alcuni campi rimanevano null — l'applicazione falliva a runtime con NPE.
Storia
Nel codice di libreria aperto, un costruttore secondario nella classe derivata ha accidentalmente evitato il costruttore primario, causando due rami diversi di inizializzazione: a volte il campo era inizializzato, altre volte no. L'errore è stato trovato solo dopo molto tempo attraverso complessi report di bug.