Constructors and init Blocks
Primary Constructor
The primary constructor is part of the class header. Parameters can have default values, so callers can skip them, and callers can use named arguments.
Example
class User(val name: String, val city: String = "Hyderabad", val isPremium: Boolean = false)
fun main() {
val a = User("Arjun")
val b = User("Meera", "Pune")
val c = User(name = "Kiran", isPremium = true)
println("${a.name} - ${a.city} - ${a.isPremium}")
println("${b.name} - ${b.city} - ${b.isPremium}")
println("${c.name} - ${c.city} - ${c.isPremium}")
}Output
Arjun - Hyderabad - false Meera - Pune - false Kiran - Hyderabad - true
init Blocks
The primary constructor cannot contain code. Put setup logic and validation in an init block. It runs every time an object is created, in the order it appears in the class (together with property initializers).
Example
class BankAccount(val holder: String, initialBalance: Double) {
val balance: Double
val accountType: String
init {
require(initialBalance >= 0) { "Balance cannot be negative" }
balance = initialBalance
println("init 1: account created for $holder")
}
init {
accountType = if (balance >= 100000) "Premium" else "Regular"
println("init 2: type is $accountType")
}
}
fun main() {
val acc = BankAccount("Ravi", 150000.0)
println("${acc.holder} has ${acc.balance}")
}Output
init 1: account created for Ravi init 2: type is Premium Ravi has 150000.0
Secondary Constructors
A class can have extra constructors written with the constructor keyword. If a primary constructor exists, every secondary constructor must call it with this(...). In modern Kotlin, default arguments usually replace secondary constructors; you still see them in Android custom views and Java interop.
Example
class Product(val name: String, val price: Double, val category: String) {
constructor(name: String, price: Double) : this(name, price, "General") {
println("Secondary constructor used for $name")
}
init {
println("init: $name created")
}
}
fun main() {
val p1 = Product("Laptop", 55000.0, "Electronics")
val p2 = Product("Notebook", 40.0)
println("${p1.name} -> ${p1.category}")
println("${p2.name} -> ${p2.category}")
}Output
init: Laptop created init: Notebook created Secondary constructor used for Notebook Laptop -> Electronics Notebook -> General
Note: Notice the order in the output: the init block runs first (as part of the primary constructor), then the body of the secondary constructor.
Exercise
Exercise: Create a class Rectangle(width, height) whose init block rejects non-positive sizes with require, and a secondary constructor Rectangle(side) that makes a square.
Show answer
class Rectangle(val width: Int, val height: Int) {
init {
require(width > 0 && height > 0) { "Sizes must be positive" }
}
constructor(side: Int) : this(side, side)
fun area() = width * height
}
fun main() {
println(Rectangle(4, 5).area()) // 20
println(Rectangle(3).area()) // 9
}