How do I define constructors and initialize class properties in Kotlin?

In Kotlin, you usually define constructors and initialize properties directly in the class header using a primary constructor.

1. Primary constructor

The most common style is:

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

This defines:

  • a class named Person
  • a read-only property name
  • a mutable property age
  • a constructor that requires both values

Usage:

fun main() {
    val person = Person("Alice", 30)

    println(person.name)
    println(person.age)

    person.age = 31
    println(person.age)
}

Here, val name: String and var age: Int are both constructor parameters and class properties.


2. Constructor parameters without properties

If you omit val or var, the parameter is only available during initialization:

class Person(name: String) {
    val uppercaseName = name.uppercase()
}

Usage:

fun main() {
    val person = Person("Alice")

    println(person.uppercaseName)
}

In this example, name is not a property. You cannot access person.name unless you declare it with val or var.


3. Initialize properties in the class body

You can initialize properties using constructor values:

class Rectangle(val width: Int, val height: Int) {
    val area: Int = width * height
}

Usage:

fun main() {
    val rectangle = Rectangle(5, 4)

    println(rectangle.area)
}

Output:

20

4. Use an init block

If you need validation or setup logic, use an init block:

class User(val username: String, val age: Int) {
    init {
        require(username.isNotBlank()) {
            "Username must not be blank"
        }

        require(age >= 0) {
            "Age must not be negative"
        }
    }
}

The init block runs when an object is created:

fun main() {
    val user = User("kotlinFan", 25)

    println(user.username)
}

5. Default constructor values

You can give constructor parameters default values:

class Product(
    val name: String,
    val price: Double = 0.0,
    val inStock: Boolean = true
)

Usage:

fun main() {
    val freeSample = Product("Sticker")
    val laptop = Product("Laptop", 999.99, false)

    println(freeSample.price)
    println(laptop.inStock)
}

6. Named arguments

Named arguments make constructor calls clearer:

class Book(
    val title: String,
    val author: String,
    val pages: Int
)

fun main() {
    val book = Book(
        title = "Kotlin Basics",
        author = "JetBrains",
        pages = 250
    )

    println(book.title)
}

7. Secondary constructors

Kotlin also supports secondary constructors, but they are less common:

class Car {
    val brand: String
    val year: Int

    constructor(brand: String, year: Int) {
        this.brand = brand
        this.year = year
    }
}

Usage:

fun main() {
    val car = Car("Toyota", 2024)

    println(car.brand)
    println(car.year)
}

However, this is usually better written with a primary constructor:

class Car(val brand: String, val year: Int)

8. Primary and secondary constructors together

If a class has a primary constructor, secondary constructors must delegate to it using this(...):

class Employee(val name: String, val role: String) {
    constructor(name: String) : this(name, "Employee")
}

Usage:

fun main() {
    val employee = Employee("Sam")
    val manager = Employee("Dana", "Manager")

    println(employee.role)
    println(manager.role)
}

9. Late initialization with lateinit

For mutable non-null properties initialized later, use lateinit var:

class Session {
    lateinit var token: String

    fun start(token: String) {
        this.token = token
    }
}

Usage:

fun main() {
    val session = Session()

    session.start("abc123")

    println(session.token)
}

Use lateinit carefully. Accessing it before initialization causes an exception.


10. Custom getters and setters

You can customize property access:

class Temperature(celsius: Double) {
    var celsius: Double = celsius
        set(value) {
            require(value >= -273.15) {
                "Temperature cannot be below absolute zero"
            }
            field = value
        }

    val fahrenheit: Double
        get() = celsius * 9 / 5 + 32
}

Usage:

fun main() {
    val temperature = Temperature(25.0)

    println(temperature.fahrenheit)

    temperature.celsius = 30.0
    println(temperature.fahrenheit)
}

Quick summary

class Person(
    val name: String,
    var age: Int = 0
) {
    init {
        require(name.isNotBlank()) {
            "Name cannot be blank"
        }
    }

    val isAdult: Boolean
        get() = age >= 18
}

This example shows:

  • val name: read-only property initialized from constructor
  • var age: mutable property with a default value
  • init: validation logic
  • isAdult: computed property

In most Kotlin code, prefer a primary constructor with val or var properties unless you specifically need more complex construction logic.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.