skip to content

Do final fields receive default values, and how does that interact with the requirement that a final field must be assigned exactly once?

level: seniorimportance: should knowfreq 35%

answer

  1. final field still zeroed transiently
  2. blank final: assign exactly once, all paths
  3. can't rely on default for a final
  4. static final → static initializer
  5. don't let 'this' escape → default leak across threads

basics

~20 s

A final field is briefly default-initialized (0/false/null) like any field, but the compiler still forces you to assign it exactly once before the constructor finishes. So you can't rely on the default as its final value.

solid answer

~50 s

Every field, including a `final` one, is first default-initialized by the JVM (0, false, '', or null) when memory is zeroed. But a `final` instance field is also a 'blank final': the compiler's definite-assignment analysis requires it to be assigned exactly once, on every constructor path, before the constructor returns, and forbids reassignment. So the default value is only a transient pre-constructor state, not the field's usable value. You cannot leave a final field unassigned and depend on the 0/null default — that's a compile error ('variable might not have been initialized'). A static final must be assigned at declaration or in a static initializer. There's also a memory-model angle: final fields correctly constructed (and not leaked via 'this' escaping the constructor) are guaranteed visible to other threads after construction without extra synchronization, which is why default-state leakage during construction is dangerous.

go deeper

for a junior

Know that final means assign-once; you can't just leave it at the default.

for a middle

Explain blank finals must be assigned on every constructor path exactly once, and the compiler error if you don't.

for a senior

Cover the transient default during construction, definite-assignment-plus-unassignment rules, static vs instance finals, and the basic JMM final-field visibility guarantee.

for a principal

Discuss safe-construction patterns (no 'this' escape), how the JMM final-field semantics enable lock-free immutable sharing, and the failure mode where default state leaks across threads.

## Recap: defaults vs. assignment Every field is **default-initialized** when the object's memory is zeroed: numeric→0, boolean→false, char→'', reference→null. Separately, the compiler may *also* require you to assign a value. For ordinary fields, assignment is optional (the default stands). For **final** fields, assignment is mandatory and constrained. ## What `final` means on a field Declaring a field `final` means it can be assigned **exactly once** and never changed afterward. A `final` field with no initializer is called a **blank final** — 'blank' because its value is deferred to the constructor (for instance fields) or a static initializer (for static fields). ## The compiler rules (definite assignment, extended) The same **definite-assignment analysis** that governs local variables is extended for finals to also check **definite *un*assignment** (it isn't assigned more than once): - A blank final **instance** field must be definitely assigned by the end of **every** constructor that doesn't delegate via `this(...)`, on **every** path. Miss one path → 'variable might not have been initialized'. - It must be assigned **at most once** — assigning twice, or assigning then reassigning, is a compile error. - A blank final **static** field must be assigned exactly once in a **static initializer block** (or at declaration). So even though the JVM transiently sets the final field to its type default, you can never *rely* on that default: the compiler won't let the field remain unset. Example: ```java class C { final int n; // blank final C(boolean b) { if (b) n = 1; // compile error: n might not be initialized } // (the b==false path leaves n unassigned) } ``` Fix by assigning on all paths or at declaration. ## Why the default still 'exists' During object construction the timeline is: (1) memory zeroed to defaults, (2) field initializers/instance blocks run, (3) constructor body runs and must assign the blank final. There is a real window where the final field holds its default. This matters if construction is buggy. ## The Java Memory Model angle The Java Memory Model gives `final` fields a special guarantee: if an object is **properly constructed** (its reference does not 'escape' — become visible to other threads — before the constructor finishes), then any thread that sees the object is guaranteed to see the correctly assigned `final` field values, with no synchronization. But if `this` leaks during construction (e.g., you register `this` with a listener inside the constructor), another thread can observe the final field still holding its **default** value. This is exactly why the transient default state is a correctness hazard and why 'don't let this escape during construction' is a rule. ## Summary Finals do get a default transiently, but you must explicitly assign them exactly once before construction completes; the default is never their resting value, and leaking the object mid-construction can expose that default to other threads.

  • Where must a blank static final field be assigned?
    At declaration or in a static initializer block, exactly once, before the class finishes initializing.
  • What happens if 'this' escapes during construction with respect to final fields?
    Another thread can observe the final field still at its default value, breaking the JMM final-field visibility guarantee that holds only for properly-constructed (non-escaped) objects.

saying these in an interview costs you the question

  • Saying a final field can be left to its default 0/null — the compiler forbids leaving it unassigned
  • Claiming finals are never default-initialized — they are, transiently, before the constructor assigns
  • Thinking final fields are automatically thread-safe even if 'this' escapes during construction
  • Believing you can assign a blank final twice on different paths

context