В Kotlin у класса может быть один primary constructor и сколько угодно secondary constructors. Отличие от Java — в Kotlin primary constructor объявляется в шапке класса и может содержать параметры и модификаторы. Secondary конструкторы всегда должны вызывать либо другой secondary конструктор, либо primary constructor, либо конструктор суперкласса (через ключевое слово super).
Ключевые особенности:
: super(...).super(...) или другой secondary/primary конструктор.Пример использования с наследованием:
open class A(val a: Int) { constructor(a: Int, str: String) : this(a) { println("Secondary in A: $str") } } class B : A { constructor(a: Int) : super(a) { println("Secondary in B") } constructor(a: Int, s: String) : super(a, s) { println("Secondary #2 in B") } }
Чем отличается подход от Java:
Можно ли в Kotlin создать дочерний класс, НЕ вызывав явно конструктор суперкласса, если в базовом классе есть только определённый конструктор?
Ответ: Нет, в отличие от Java, в Kotlin вызов конструктора суперкласса обязателен и явно указывается либо в "голове" класса, либо после ключевого слова : super().
Пример ошибки:
open class Base(val x: Int) class Derived : Base // Ошибка компиляции!
История
В проекте-микросервисе после миграции на Kotlin забыли про явное указание родительского конструктора: конструктор суперкласса с обязательным параметром не вызывался, сервис не компилировался, потребовалось рефакторить сигнатуры.
История
Android-проект имел глубокую иерархию (Activity → BaseActivity → CustomActivity), добавление secondary constructor терял параметры, в итоге шел вызов не того базового конструктора, и часть полей оставалась null — приложение падало на runtime с NPE.
История
В открытом библиотечном коде secondary constructor в дочернем классе случайно обошёл primary constructor, что привело к двум разным веткам инициализации: иногда поле было инициализировано, иногда — нет. Ошибку нашли только спустя много времени по сложным баг-репортам.