Understand Kotlin Multiple Constructors
Simple examples to showcase primary and secondary / multiple constructors in Kotlin
In Kotlin, you have one primary and many secondary constructors.
Primary Constructor
This is primary constructor with one parameter.
class Example constructor(private val param1: String) {
init {
println("init is called.")
}
}
You can also omit the constructor
keyword.
class Example(private val param1: String) {
init {
println("init is called.")
}
}
You can NOT initialize in primary constructor. Instead, you need to initialize your code in init{}
block.
Secondary Constructor
There are 2 secondary constructors below.
class Example(private val param1: String) {
init {
println("init is called.")
}
//First secondary constructor
constructor(
param1: String,
param2: String) : this(param1) {
println("Second constructor is called")
}
//Second secondary constructor
constructor(
param1: String,
param2: String,
param3: String) : this(param1) {
println("Third constructor is called")
}
}
Few important notes here:
- You must call the primary constructor (e.g. calling
this(param1)
). Not really! See next section - Call Another Secondary Constructor - You can declare
var
orval
in the secondary constructor parameter - You can initialize your code in secondary constructor
Please note that primary constructor together with the init{}
block is called first before the secondary constructor initialization.
So, if I call the third constructor,
val obj = Example(param1="1", param2="2", param3="3")
the output will be like this.
init is called.
Third constructor is called
Call Another Secondary Constructor
Instead of calling the primary constructor in your secondary constructor, you can also call another secondary constructor.
In this example, the second secondary constructor calls the first secondary constructor.
class Example(private val param1: String) {
init {
println("init is called.")
}
//First secondary constructor
constructor(
param1: String,
param2: String) : this(param1) {
println("Second constructor is called")
}
//Second secondary constructor
constructor(
param1: String,
param2: String,
param3: String) : this(param1, param2) {
println("Third constructor is called")
}
}
If I call the third constructor, the output looks like this:
init is called.
Second constructor is called
Third constructor is called
Empty Primary Constructor
This is an empty primary constructor and secondary constructor example.
class Example() {
init {
println("init is called.")
}
constructor(param1: String): this() {
println("Second constructor is called")
}
}
However, you don't really need to call this()
in your secondary constructor. You also need to change Example()
to Example
.
class Example {
init {
println("init is called.")
}
constructor(param1: String) {
println("Second constructor is called")
}
}
Secondary Constructor Use case
I encountered the needs of using secondary constructor when I want to inject the Hilt dependency into my View Model.
I have code like this where preview
parameter is used for @preview
jetpack compose. It is set to true
only in @preview
. However, if I port this change to use Hilt
dependency injection, it fails to inject this dependency.
class MainViewModel(
private val repository: ArticlesRepository,
preview: Boolean = false,
) : ViewModel() {
/*...*/
}
Thus, I break this to secondary constructor below.
class MainViewModel(
private val repository: ArticlesRepository) : ViewModel() {
constructor (
repository: ArticlesRepository,
preview: Boolean) : this(repository) {
/*...*/
}
}
So I use @Inject constructor
for the primary constructor and the secondary constructor is used for @preview
.
With Hilt
implementation, it looks like this
@HiltViewModel
class MainViewModel
@Inject constructor(
private val repository: ArticlesRepository,
) : ViewModel() {
constructor (
repository: ArticlesRepository,
preview: Boolean) : this(repository) {
/*...*/
}
/*...*/
}
Conclusion
I haven't used a lot of multiple constructors, have you? So, I documented this here for my future reference.