In Kotlin, every class can have one primary constructor and several secondary constructors. Constructor delegation is a mechanism where a secondary constructor must either directly call the primary constructor or another secondary constructor of the same class (which eventually leads to the primary). If a class inherits from another, every secondary constructor of the derived class must explicitly delegate the call to the superclass constructor if necessary.
In Java, constructors can directly call each other using this() or super(), overloading constructors in various combinations. In Kotlin, this concept is formalized: a class can have only one primary constructor, and secondary constructors may use delegation logic that must be explicitly stated.
Improper implementation of delegation can lead to compilation errors: a primary constructor cannot be omitted if it is declared, and a super constructor must be called in a derived class if the base class does not have a default constructor. It is important to understand when init blocks are called, how parameters are passed, and how delegation affects the order of initialization.
An example of basic delegation:
class Person(val name: String) { constructor(name: String, age: Int) : this(name) { println("Secondary constructor: $name, $age") } }
If inheritance is used:
open class Parent(val name: String) class Child : Parent { constructor(name: String) : super(name) { println("Child secondary: $name") } }
Can a secondary constructor not delegate to anything?
No, the compiler will require an explicit call to this(...) or super(...), otherwise, it will result in an error.
In what order do initializations and init blocks execute if a secondary constructor is used?
The primary constructor and init block(s) always execute first, followed by the initialization code of the secondary constructor.
class Demo(val value: String) { init { println("init block") } constructor(value: String, code: Int) : this(value) { println("secondary: $code") } } Demo("kotlin", 7) // output: // init block // secondary: 7
Can a descendant call only the primary constructor of the parent if its secondary constructor exists?
Yes, but only explicitly through super(...), secondary constructors are not directly visible to descendants.
In a project, a secondary constructor does not call the primary, crucial initialization (e.g., setting required fields) does not take place, leading to bugs and crashes at runtime.
Pros:
Cons:
All secondary constructors strictly delegate through this(...), necessary initialization is centralized in primary/init, and the structure is clear for maintenance.
Pros:
Cons: