skip to content

How do field initializers and instance initializer blocks interact when assigning final fields, and in what order do they run relative to the constructor?

level: seniorimportance: should knowfreq 40%

answer

  1. Order: super → initializers+blocks (source order) → constructor body
  2. Initializers/blocks run before the constructor body
  3. Assign a final in exactly one of the three places
  4. this(...) skips initializers for that constructor
  5. Illegal forward reference if you read a later-declared field

basics

~20 s

Field initializers and instance initializer blocks run in the order they appear in the source, after the superclass constructor and before the rest of the constructor body. A final field can be set in one of these places or in the constructor, but only once total.

solid answer

~50 s

For each new object, Java runs initialization in a fixed order: first the superclass constructor (via the implicit or explicit super(...) call), then the instance field initializers and instance initializer blocks in the exact textual order they appear in the class body, and finally the remaining statements of the constructor body. A final instance field must be definitely assigned exactly once across all of this. So you can assign it in a field initializer, or in an instance block, or in the constructor body — but exactly one of these may assign it on any given path. Because initializers and blocks run before the constructor body, a final assigned there is already set by the time the constructor body runs, and the constructor must not reassign it. The compiler tracks definite assignment through this whole sequence. This ordering also explains forward-reference rules: you generally cannot read a field in an initializer that appears textually later.

go deeper

for a junior

Knows initializers and the constructor both run during object creation.

for a middle

Can state that instance initializers and blocks run before the constructor body, in source order.

for a senior

Explains the full super → initializers/blocks → constructor-body order, how a final must be assigned once across all three, and forward-reference rules.

for a principal

Reasons about this(...) vs super(...) chains, when initializers fire per object, and how initialization order interacts with inheritance and overridable-method-in-constructor hazards.

## The pieces involved Three mechanisms can set instance state during construction: 1. **Field initializers** — the `= value` part of a field declaration: `private final int a = compute();`. 2. **Instance initializer blocks** — bare `{ ... }` blocks in the class body (not `static {}`): `{ a = compute(); }`. 3. **Constructor bodies** — the statements inside a constructor. ## The construction order (for one object) When `new T(...)` runs, Java does the following **in this order**: 1. Allocate the object; all fields get default values (0/false/null) — invisible to you for finals. 2. The constructor's **super(...) call** runs (explicit, or an implicit `super()` if you wrote none), fully constructing the superclass portion first. 3. **Instance field initializers and instance initializer blocks run, in the exact order they appear in the source text**, interleaved by position. If a field initializer is written above a block, it runs first; if below, it runs after. 4. The **rest of the constructor body** runs (the statements after the super/this call). Key consequence: by the time the constructor body executes its own statements, all field initializers and instance blocks have already run. (Static initializers and static field initializers are a *separate*, class-load-time sequence and run only once for the class, not per object — don't conflate them with instance initialization.) ## How final fits in A `final` instance field must be **definitely assigned exactly once** considering this whole sequence as one flow. So: - You may assign it in a field initializer **or** an instance block **or** the constructor — but on any path, **only one** of these may assign it. - If a field initializer or instance block already assigns the final, the constructor body must **not** assign it again (that would be a second assignment). - Different constructors can rely on a field initializer/block having set the final, since those run before every constructor body. ## Why order matters: forward references Because initializers run top-to-bottom, you generally **cannot read** a field in an initializer that is declared *later* in the class (a 'illegal forward reference'): ```java class C { final int a = b + 1; // ERROR: b not yet initialized / illegal forward reference final int b = 2; } ``` Reordering so `b` is declared first fixes it. ## Worked example with a block ```java class Box { private final int w; private final int h; { h = 10; } // instance block sets h Box(int w) { this.w = w; // constructor sets w // must NOT set h again — the block already did } } ``` Here `h` is set by the instance block (runs before the constructor body) and `w` by the constructor; each final is assigned exactly once. ## A subtle constructor-delegation note If a constructor delegates with `this(...)` instead of `super(...)`, the **field initializers and instance blocks do NOT run for the delegating constructor** — they run only for the constructor that ultimately reaches `super(...)`. They run once per object, not once per constructor in a `this(...)` chain. This affects where a final ends up assigned and is a common source of confusion. ## Summary Instance field initializers and instance blocks run in source order, after `super(...)` and before the constructor body. A `final` field is assigned exactly once across that combined flow; the compiler's definite-assignment analysis spans all three mechanisms, and source order also governs legal forward references.

  • If a constructor uses this(...) to delegate, do the instance field initializers run for it?
    They run once per object, triggered by the constructor that invokes super(...). A constructor that delegates via this(...) does not itself trigger the initializers/blocks again; they run as part of the delegated-to chain reaching super().
  • Why can't a field initializer read a field declared below it?
    Initializers execute in source order, so a later-declared field has not been initialized yet. The compiler flags this as an illegal forward reference.

saying these in an interview costs you the question

  • Assuming instance blocks run after the constructor body
  • Confusing static initialization (class load, once) with instance initialization (per object)
  • Setting a final in both an initializer and the constructor
  • Thinking field initializers run on every constructor in a this(...) chain

context