You are currently viewing Kotlin Constructor

Kotlin Constructor

Constructor

A constructor is a special function or code block that is used to initialize an instance of a class. It is invoked when an object of the class is created. It defines how an object of a class is created and sets up its initial state.

There are two types of constructors in Kotlin:

1. Primary Constructor:
2. Secondary Constructor:

1. Primary Constructor:

  • The primary constructor is defined in the class header itself, right after the class name.
  • It can have properties (parameters) that are used to initialize the class.
  • It is used to set up the initial state of the class.

Here’s the syntax for the primary constructor:

class MyClass(parameter1: Type1, parameter2: Type2, ...) {
    // Class body
}

In this syntax:

  • MyClass is the name of the class.
  • parameter1, parameter2, etc., are the parameters of the constructor.
  • Type1, Type2, etc., are the types of the parameters.

Kotlin program of primary constructor:

class Person(val firstName: String, val lastName: String, val age: Int) {
    fun personDetails(): String {
        return "Name: $firstName $lastName\nAge: $age"
    }
}

fun main() {
    val person = Person("John", "Doe", 25)
    val details = person.personDetails()
    println(details)
}
/**
Output
Name: John Doe
Age: 25
**/

Here, Person is the class, and it has a primary constructor , firstName, lastName, and age are parameters of the primary constructor, they are declared as properties of the class.

Note: If you don’t declare any visibility modifier (like public, private, etc.) for the constructor, it is public by default.

Kotlin program of primary constructor with initializer block

class Person(firstName: String, lastName: String, age: Int) {
    // Properties defined in the primary constructor.
    val fullName: String
    
    init {
        // Code inside init block is executed when an instance is created.
        fullName = "$firstName $lastName"
        println("init executed ")
    }
}

fun main(){
    val p1 = Person(firstName = "Green", lastName = "Bruce",23)
    print(p1.fullName)
}

Output:


init executed 
Green Bruce

In this example, Person class has a primary constructor that takes firstName, lastName, and age as parameters. The init block is used to execute code during instance initialization.

2. Secondary Constructor:

  • A class can have one or more secondary constructors.
  • They are defined using the constructor keyword.
  • Secondary constructors must call the primary constructor or another secondary constructor using the this keyword.

Secondary constructors can be defined in a class using the constructor keyword. Secondary constructors allow you to provide additional ways to initialize your class. Here’s the syntax for a secondary constructor:

class MyClass {
    // Primary constructor and class body

    // Secondary constructor
    constructor(parameter1: Type1, parameter2: Type2, ...) {
        // Initialization code
    }

    // Additional methods, properties, etc.
}

In this syntax:

  • class MyClass is the class declaration.
  • The primary constructor, if any, is declared within the class header.
  • The secondary constructor is declared using the constructor keyword followed by its parameters.
  • Inside the secondary constructor’s body, you can write the code necessary to initialize the class or perform additional logic.

Kotlin Program Of Secondary Constructor

class Person {
    var name: String = ""
    var age: Int = 0

    constructor(name: String, age: Int) {
        this.name = name
        this.age = age
    }


}

fun main() {
    val person1 = Person("John", 25)
    println("Name: ${person1.name}, Age: ${person1.age}")


}
/**
Output
Name: John, Age: 25
*/

In above example secondary constructor is defined that takes two parameters (name and age). Inside the secondary constructor, the properties name and age are initialized with the values passed as parameters using this.

Kotlin Program Of multiple secondary constructors

class Person {
    var firstName: String = ""
    var lastName: String = ""
    var age: Int = 0

    // First  constructor
    constructor(firstName: String, lastName: String, age: Int) {
        this.firstName = firstName
        this.lastName = lastName
        this.age = age
        println("First constructor called")
    }

    // Secondary constructor without age parameter
    constructor(firstName: String, lastName: String) : this(firstName, lastName, 0) {
        println("Secondary constructor without age parameter called")
    }

    // Secondary constructor without any parameters
    constructor() : this("Unknown", "Unknown", 0) {
        println("Secondary constructor without any parameters called")
    }

    // Method
    fun displayDetails() {
        println("Name: $firstName $lastName, Age: $age")
    }
}

fun main() {
    // Using the primary constructor
    val person1 = Person("John", "Doe", 25)
    person1.displayDetails()
    println()

    // Using the secondary constructor without age parameter
    val person2 = Person("Jane", "Smith")
    person2.displayDetails()
    println()


    // Using the secondary constructor without any parameters
    val person3 = Person()
    person3.displayDetails()
    println()

}

In this example:

  • The class Person has a primary constructor and two secondary constructors.
  • The constructor(firstName: String, lastName: String, age: Int) initializes the firstName, lastName, and age properties using this.
  • The constructor(firstName: String, lastName: String) is the cases where the age is provided by this(..), this(..) syntax will call first secondary constructor.
  • The constructor(firstName: String, lastName: String) is for cases where only the name is provided, and it calls the first constructor by providing a default value for age using this(..).
  • The third secondary constructor constructor() is for where no parameters are provided, and this(..) delegates to the second constructor by providing default values for name and age.

When you run the main function, you’ll see that each constructor is called based on how the Person instances are created.

Output

First constructor called
Name: John Doe, Age: 25
First constructor called
Secondary constructor without age parameter called
Name: Jane Smith, Age: 0
First constructor called
Secondary constructor without any parameters called
Name: Unknown Unknown, Age: 0

Execution Order Of Static Initializer, Primary Constructor, init Blocks:

class MyClass {
    companion object {
        init {
            println("Static Initializer")
        }
    }

    init {
        println("Init Block 1")
    }

    val property1: String

    constructor(param: String) {
        println("Constructor")
        property1 = param
    }

    init {
        println("Init Block 2")
    }
}

fun main() {
    val instance = MyClass("Hello")
}

//Output
Static Initializer
Init Block 1
Init Block 2
Constructor

In this example, you can see the order of execution for the static initializer, init blocks, and the constructor. Keep in mind that the static initializer is executed only once when the class is loaded, while the init blocks and primary constructor are executed each time an instance is created.

Note: if In the class , primary constructor is deined with no properties, and define the secondary constructor. primary constructor must be called using this() with their params otherwise will get an error(Primary constructor call expected)

class Person() {
    var fullName: String? = null


    constructor(fName: String) : this() {
        this.fullName = fName
        println("no parameter constructor run ")
        println("$fullName")
    }
}

Note: In below example, the primary constructor is implicitly called before the body of the secondary constructor. So, when an instance of Person is created using the secondary constructor, the primary constructor is automatically invoked.

class Person {
    var fullName: String? = null

    constructor(fName: String){
        this.fullName = fName
        println("no parameter constructor run ")
        println("$fullName")
    }
}

In above case primary constructor is responsible for initializing properties. the fullName property is initialized directly in the primary constructor with a default value of null. Therefore, when you create an instance using the secondary constructor, the fullName property is already initialized.

Kotlin program of calling one constructor from another ?

One constructor can be called from another using the this keyword. This is done in the secondary constructor to ensure that the object is properly initialized.

 1. Example of Secondary constructor that calls the primary constructor

class Person(val name: String, val age: Int) {

    init {
        println("Primary constructor: Name: $name, Age: $age")
    }

    // Secondary constructor calling the primary constructor
    constructor(name: String) : this(name, 0) {
        println("Secondary constructor: Default age (0) assigned.")
    }
}

fun main() {
    // Creating an instance using the primary constructor
    val person1 = Person("John", 30)

    // Creating an instance using the secondary constructor
    val person2 = Person("Jane")

    // Output:
    // Primary constructor: Name: John, Age: 30
    // Secondary constructor: Default age (0) assigned.
}

In this example The class also has a secondary constructor that takes a single parameter name. This secondary constructor calls the primary constructor using this(name, 0), providing a default value of 0 for the age parameter.

2. Example of one secondary constructor calls another secondary constructor :

Here’s an example of a Kotlin class with two secondary constructors, where one secondary constructor calls another:

class Person {
    var fullName: String = ""
    var age: Int = 0


    // Secondary constructor #1
    constructor(firstName: String, lastName: String) {
        fullName = "$firstName $lastName"
    }


    // Secondary constructor #2 - calls the first constructor
    constructor(firstName: String, lastName: String, age: Int) : this(firstName, lastName) {
        this.age = age
        fullName = "$fullName ($age years old)"
    }
}

In this example, we have a Person class with two secondary constructors:

  • Secondary Constructor #1:
    • Takes firstName and lastName as parameters.
    • Initializes the fullName property by concatenating the first and last names.
  • Secondary Constructor #2:
    • Takes firstName, lastName, and age as parameters.
    • Calls the first secondary constructor using this(firstName, lastName).
    • Initializes the age property and updates the fullName to include the age.

Example of creating Person objects:

class Person {
    var fullName: String = ""
    var age: Int = 0


    // Secondary constructor #1
    constructor(firstName: String, lastName: String) {
        fullName = "$firstName $lastName"
    }


    // Secondary constructor #2 - calls the first constructor
    constructor(firstName: String, lastName: String, age: Int) : this(firstName, lastName) {
        this.age = age
        fullName = "$fullName ($age years old)"
    }
}

fun main() {
    val person1 = Person("Alice", "Smith")
    println("Full Name: ${person1.fullName}, Age: ${person1.age}") // Output: Full Name: Alice Smith, Age: 0


    val person2 = Person("Bob", "Johnson", 25)
    println("Full Name: ${person2.fullName}, Age: ${person2.age}") // Output: Full Name: Bob Johnson (25 years old), Age: 25
}

Output

Output
 Full Name: Alice Smith, Age: 0
Full Name: Bob Johnson (25 years old), Age: 25

Example of Calling constructor of parent class from child class

you can call a constructor of the parent class from the child class by using the super keyword.

1. Example of calling primary constructor of parent from child class

open class Parent(val name: String) {
    init {
        println("Initializing Parent with name: $name")
    }
}


class Child(name: String, val age: Int) : Parent(name) {
    init {
        println("Initializing Child with age: $age")
    }
}

In this Example, The Child class extends Parent and takes name and age as parameters in its primary constructor. The : Parent(name) syntax indicates that the Parent constructor with the name parameter should be called.

When you create an instance of Child, both the Parent and Child initializers will be called:

fun main() {
    val child = Child("Alice", 30)
    // Output:
    // Initializing Parent with name: Alice
    // Initializing Child with age: 30
}

when a Child object is created, the Parent class’s constructor is called first (via super(name)), followed by the Child class’s constructor.

2. Calling parent class secondary constructor from child class secondary constructor

when you need to call a secondary constructor of the parent class from a secondary constructor of the child class, you use the super keyword with the appropriate arguments.

open class Parent {
    var firstName: String = ""
    var lastName: String = ""


    constructor(firstName: String, lastName: String) {
        this.firstName = firstName
        this.lastName = lastName
        println("Parent Secondary Constructor Called")
    }
}


class Child : Parent {
    var age: Int = 0


    constructor(firstName: String, lastName: String, age: Int) : super(firstName, lastName) {
        this.age = age
        println("Child Secondary Constructor Called")
    }
}

fun main() {
    val child = Child("Alice", "Smith", 30)
    println("Name: ${child.firstName} ${child.lastName}, Age: ${child.age}")
}

Inside the Child class’s constructor, we use super(firstName, lastName) to call the secondary constructor of the Parent class with the appropriate arguments. This ensures that the properties firstName and lastName are initialized in the Parent class.

if you run this program, you will see this output

Parent Secondary Constructor Called
Child Secondary Constructor Called
Name: Alice Smith, Age: 30