Kotlin – 13 – Constructors in Kotlin

Constructors in Kotlin play a crucial role in initializing objects of a class. They define how objects are created and what values they should have when they are first instantiated. In this guide, we’ll explore constructors in Kotlin, including primary constructors, secondary constructors, and how to use them effectively.

Primary Constructors

A primary constructor in Kotlin is defined within the class header and is the most common way to create objects of a class. It allows you to specify the parameters that should be provided when creating an instance of the class. Here’s the basic syntax:

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

For example, let’s create a simple Person class with a primary constructor that takes name and age as parameters:

class Person(val name: String, val age: Int) {
    // Class body
}

With this primary constructor, you can create Person objects by providing values for name and age: val person = Person("Alice", 30)

Properties and Initialization

In Kotlin, when you define constructor parameters with the val or var keyword, they automatically become properties of the class. In the example above, name and age are properties of the Person class. You can access and modify these properties like any other class member.

Primary constructors can also include code in the class body, which runs as part of object initialization. For example, you can add an initialization block to the Person class:

class Person(val name: String, val age: Int) {
    init {
        println("$name has been created with age $age")
    }
}

In this case, the init block is executed when a Person object is created, printing a message indicating the object’s creation.

Secondary Constructors

In addition to primary constructors, Kotlin allows you to define secondary constructors using the constructor keyword. Secondary constructors are used when you need to provide additional ways to create objects or when you want to customize object initialization. Here’s the syntax for a secondary constructor:

class ClassName {
    constructor(parameter1: Type1, parameter2: Type2, ...) {
        // Secondary constructor body
    }
}

Here’s an example of a class with both a primary and a secondary constructor:

class Person(val name: String, val age: Int) {
    constructor(name: String) : this(name, 0) {
        println("$name has been created with age $age")
    }
}

In this example, the primary constructor takes name and age, and the secondary constructor takes only name. The secondary constructor delegates to the primary constructor using the this keyword with default age 0 for cases where the age is not provided.

Default Values and Overloading

In Kotlin, you can provide default values for constructor parameters, allowing you to create objects without supplying values for all parameters. Default values are specified in the primary constructor, like this:

class Person(val name: String, val age: Int = 0) {
    // Class body
}

In this example, the age parameter has a default value of 0. This means you can create Person objects without specifying an age, and it will default to 0.

You can also overload constructors by providing multiple constructors with different parameter lists. Here’s an example of a Person class with overloaded constructors:

class Person(val name: String, val age: Int) {
    constructor(name: String) : this(name, 0) {
        println("$name has been created with age $age")
    }
    constructor(name: String, age: Int, city: String) : this(name, age) {
        println("$name lives in $city")
    }
}

In this example, there are two secondary constructors that provide different ways to create Person objects with varying levels of information.

Command and Example

Here’s an example that demonstrates primary and secondary constructors in Kotlin:

class Car(val make: String, val model: String, var year: Int) {
    init {
        println("A new $year $make $model has been created")
    }

    constructor(make: String, model: String) : this(make, model, 2023) {
        println("A new $year $make $model has been created (default year)")
    }
}

fun main() {
    val car1 = Car("Toyota", "Camry", 2022)
    val car2 = Car("Honda", "Civic")
}

In this example, we have a Car class with a primary constructor that takes make, model, and year. The class also has an init block that runs during object initialization. Additionally, there’s a secondary constructor that allows you to create cars without specifying the year, defaulting to 2023.

The main function demonstrates creating two Car objects using different constructors, showing how primary and secondary constructors work together to initialize objects.