In what order do the primary constructor's property initializers, init blocks, and a secondary constructor body execute?
answer
- Primary runs first (delegation forces it)
- Initializers + init blocks interleave in source order
- Secondary body runs last
- Chain: primary first, bodies unwind outward
- Init blocks can't see secondary-only params
basics
~10 sFirst the primary constructor runs: property initializers and init blocks execute top to bottom. Then the secondary constructor's body runs afterward. So shared setup happens before the secondary-specific code.
solid answer
~30 sBecause a secondary constructor must delegate to the primary, the primary's initialization always happens first. Property initializers and init blocks execute in the order they appear in the class body, interleaved, as part of the primary constructor. Only after that does the delegating secondary constructor's body run. So the effective order is: evaluate the secondary's delegation arguments, run the primary constructor (initializers + init blocks in source order), then run the secondary constructor body. With an indirect chain, the deepest delegation target (primary) runs first, then each secondary body unwinds from primary outward to the originally-called constructor.
code
kotlin · 6 linesclass Demo(val a: Int) {
val b = "b".also { println("init b") }
init { println("init block, a=$a") }
constructor(a: Int, x: Int) : this(a) { println("secondary, x=$x") }
}
// Demo(1, 9): init b -> init block, a=1 -> secondary, x=9go deeper
Knows the primary runs before the secondary body; can read simple printed output order.
Explains interleaving of initializers and init blocks by source order and where the secondary body fits.
Reasons about chains, scope of secondary parameters, and risks of reading half-initialized state.
Designs initialization so invariants hold regardless of which constructor is entered, avoiding this-leaks and order-dependent bugs.
## The big picture Because delegation forces the **primary constructor to run first**, the order is predictable. The pieces involved: - **Property initializers** — the `= ...` on a property at class level. - **`init { }` blocks** — initializer blocks. - **Secondary constructor body** — the `{ }` of the secondary constructor. ## Execution order (primary + one secondary) 1. The secondary constructor's **delegation arguments** are evaluated. 2. The **primary constructor** executes: property initializers and `init` blocks run **interleaved, in the order they appear** in the class body (top to bottom). 3. The **secondary constructor body** runs. ```kotlin class Demo(val a: Int) { val b = log("b initializer") init { log("init 1, a=$a") } val c = log("c initializer") init { log("init 2") } constructor(a: Int, extra: Int) : this(a) { log("secondary body, extra=$extra") } } private fun log(m: String): Int { println(m); return 0 } // Demo(1, 99) prints: // b initializer // init 1, a=1 // c initializer // init 2 // secondary body, extra=99 ``` Note: `init` blocks and property initializers are **interleaved by source order** — not "all initializers then all inits". ## Indirect chains For `secondaryB -> secondaryA -> primary`: 1. Primary runs (initializers + init blocks). 2. `secondaryA` body runs. 3. `secondaryB` body runs. The **deepest target (primary) executes first**, then bodies unwind outward. ## Practical consequences - Code in a secondary body can safely read properties initialized by the primary path — they're already set. - Conversely, property initializers/init blocks **cannot** see values that exist only as secondary-constructor parameters, because they run before the secondary body and those parameters aren't in scope there. - Avoid leaking `this` from an `init` block into code that depends on the secondary body having run.
- Can an init block reference a parameter that only exists on a secondary constructor?No. init blocks run as part of the primary path and only see primary constructor parameters and class-level declarations. Secondary-only parameters are out of scope there.
- If two init blocks and two property initializers are interleaved, what determines their order?Their textual order in the class body. They execute top-to-bottom regardless of being an initializer or an init block.
saying these in an interview costs you the question
- Claiming the secondary body runs before init blocks
- Saying all property initializers run before all init blocks (they interleave by source order)
- Thinking init blocks can read secondary-constructor parameters
- Believing each secondary constructor re-runs the init blocks (they run once, in the primary)