Classes and primary constructors
A class is a blueprint; an object is one thing built from it. In Kotlin the most common constructor is written in the class header itself — the primary constructor. Putting val or var in front of a parameter turns it into a property in one step, so a class that would be twenty lines of Java is one line here. There is no new keyword: you call the class like a function.
class User(val name: String, var age: Int, val country: String = "IN")
fun main() {
val ada = User("Ada", 36)
val linus = User(name = "Linus", age = 28, country = "FI")
ada.age += 1
println("${ada.name} ${ada.age} ${ada.country}")
println("${linus.name} ${linus.age} ${linus.country}")
}Ada 37 IN
Linus 28 FIRemove val from name and read the error you get on ada.name. A parameter without val/var is only visible during construction.
Code that must run when an object is created goes in an init block. A class can have several; they run top to bottom, interleaved with property initialisers in the order they appear in the source. A secondary constructor (constructor(...) in the body) is an alternative way in, and it must delegate to the primary constructor with : this(...) — so the primary constructor and every init block always run first.
class Rect(val width: Int, val height: Int) {
val area = width * height
init {
require(width > 0 && height > 0) { "sides must be positive" }
println("init: ${width}x$height, area $area")
}
constructor(side: Int) : this(side, side) {
println("secondary: a square")
}
}
fun main() {
Rect(3, 4)
Rect(5)
val bad = runCatching { Rect(0, 2) }
println(bad.exceptionOrNull()?.message)
}init: 3x4, area 12
init: 5x5, area 25
secondary: a square
sides must be positiveIn Kotlin, default arguments usually replace secondary constructors; keep secondary constructors for Java interop or genuinely different inputs.
class Rect(val width: Int, val height: Int) {val area = width * heightinit { println("init $area") }constructor(side: Int) : this(side, side) {println("secondary")}}val r = Rect(5)
Rect(5) matches the secondary constructor (one Int).
side | 5 |
All 7 steps as a table
| Step | Line | What happened | Variables now |
|---|---|---|---|
| 1 | 8 | Rect(5) matches the secondary constructor (one Int). | side = 5 |
| 2 | 4 | Before its own body runs, the secondary constructor delegates with this(side, side) to the primary constructor. | |
| 3 | 1 | The primary constructor stores the two properties. | width = 5 height = 5 |
| 4 | 2 | Property initialisers and init blocks run in source order. First area. | area = 25 |
| 5 | 3 | Then the init block. | |
| 6 | 5 | Only now does the secondary constructor's own body run. | |
| 7 | 8 | The finished object is assigned. | r = Rect(5x5) |
Missing a constructor argument
class User(val name: String, val age: Int)
fun main() {
val u = User("Ada")
println(u.name)
}Main.kt:4:13: error: no value passed for parameter 'age'.
val u = User("Ada")
^^^^Every primary-constructor parameter without a default value is required. Kotlin never fills in 0 or null for you.
Pass the argument, or give the parameter a default in the class header if a sensible one exists.
class User(val name: String, val age: Int = 0)
fun main() {
val u = User("Ada")
println(u.name)
}