How does `init` block timing relate to companion-object initialization and to secondary constructors with `this(...)` delegation?
answer
- Companion init: once, at class load, before instances
- init blocks: per instance, declaration order
- Secondary must delegate via : this(...)
- Delegation runs primary+init BEFORE secondary body
- Order: companion -> params -> props/init -> secondary body
basics
~20 sThe companion object initializes once when the class is first loaded, before any instance exists. init blocks run for each instance. A secondary constructor first delegates to the primary (running init), then runs its own body.
solid answer
~40 sThere are three distinct phases. (1) **Companion-object / static init**: a `companion object`'s property initializers and `init` run **once**, at class load, before any instance — like JVM static initialization. (2) **Per-instance primary construction**: the primary-constructor parameters bind, then property initializers and `init {}` blocks run top-to-bottom — **every** time you create an instance. (3) **Secondary constructors**: a secondary constructor must delegate to the primary (directly or transitively) via `: this(...)`. That delegation runs the **entire primary sequence — including all `init` blocks — first**, and only then does the secondary constructor's own `{ ... }` body execute. So `init` blocks always run before a secondary constructor's body, and the companion's init has already run long before either.
code
kotlin · 7 linesclass Widget(val id: Int) {
companion object { init { println("loaded once") } }
init { println("init for id=$id") }
constructor() : this(0) { println("secondary body") }
}
// first Widget(): "loaded once", "init for id=0", "secondary body"
// second Widget(7): only "init for id=7" (companion already loaded)go deeper
Knows companion init runs once and instance init runs per object.
Explains secondary constructors delegate to the primary and that init runs before the secondary body.
Lays out the full companion -> primary/init -> secondary-body timeline and places setup logic accordingly.
Reasons about class-load timing, singleton/companion side effects, and where to enforce invariants for testability and correctness.
## Three initialization timelines ### 1. Companion object (once, at class load) ```kotlin class Service { companion object { val ID = computeId() // runs once, at class load init { log("class loaded") } } } ``` A `companion object` is a singleton tied to the class. Its initializers and `init` block run **once**, when the class is first referenced/loaded — analogous to a Java `static {}` block. This happens **before any instance** is created and is **not** repeated per instance. ### 2. Per-instance primary construction (every instance) When you call a constructor that resolves to the primary, parameters bind, then the property-initializer/`init` sequence runs top-to-bottom (see the ordering rule). This repeats for **every** instance. ### 3. Secondary constructors and `this(...)` delegation Kotlin requires every **secondary constructor** to delegate to the primary constructor, directly or through another secondary, using `: this(...)`: ```kotlin class Box(val w: Int, val h: Int) { init { println("primary/init, area=${w * h}") } constructor(side: Int) : this(side, side) { println("secondary body") } } // Box(5) prints: "primary/init, area=25" THEN "secondary body" ``` The delegation `this(side, side)` runs the **whole primary sequence — all property initializers and all `init` blocks — first**. Only after that does the secondary constructor's body run. So **`init` always precedes a secondary body**. ## Ordering summary 1. (Once) companion-object initializers + companion `init`. 2. (Per instance) primary-constructor params bind. 3. (Per instance) property initializers + `init {}` blocks, in declaration order. 4. (Per instance, if via a secondary ctor) the secondary constructor body. ## Why it matters - Put **shared, instance-independent** setup (constants, registries) in the companion. - Put **per-instance invariants** in `init`. - Don't put critical validation only in a secondary body — it won't run for instances created via the primary, and it runs **after** `init` anyway.
- Does the companion init run again for the second instance?No. It runs exactly once at class load; only the per-instance init sequence repeats.
- Can a secondary constructor's body run before the init blocks?No. Delegation to the primary runs all init blocks first; the secondary body runs afterward.
Companion init is opening the shop once in the morning; each customer (instance) triggers the per-order init; a special-order form (secondary ctor) is processed only after the standard order (primary/init) is filled.
saying these in an interview costs you the question
- Saying companion init runs per instance
- Thinking a secondary body runs before init blocks
- Believing a secondary constructor can skip primary delegation
- Putting per-instance validation only in a secondary body
- Confusing companion init order with instance init order