What initialization-order pitfalls can produce wrong values, NullPointerExceptions, or ExceptionInInitializerError, and how do you avoid them?
answer
- forward static reference -> default value
- virtual call in ctor -> NPE/defaults
- static init throw -> ExceptionInInitializerError then NoClassDefFoundError
- cyclic statics -> defaults mid-cycle
- ctor body overwrites field initializer
basics
~20 sCommon traps: a static field reads another static field declared later (gets default value), a constructor calls an overridable method that sees uninitialized subclass fields, and an exception in a static initializer becomes an ExceptionInInitializerError that permanently breaks the class. Avoid by ordering declarations carefully and not calling overridable methods from constructors.
solid answer
~50 sThree families of bugs come from initialization order. First, forward reference among statics: if a static initializer reads a static field declared textually later, it sees that field's default (0/null), because static initializers run in source order. Second, the virtual-call-in-constructor trap: a constructor (or instance initializer) calls an overridable method, which dispatches to a subclass override that reads subclass fields not yet initialized, so it sees defaults or throws NPE. Third, exceptions during static initialization: an uncaught exception in a static initializer is wrapped in ExceptionInInitializerError, and the class is marked erroneous — every later use throws NoClassDefFoundError, which is confusing because the real cause was one-time. Avoid these by ordering static declarations so dependencies come first, never calling overridable methods from constructors, keeping static initializers simple, and handling errors so they don't escape static init. Cyclic static dependencies between two classes can also yield default values.
go deeper
Recognizes that constructor body overwrites field initializers and that order matters.
Can identify the forward-static-reference default-value bug and the ctor-body-overwrite confusion.
Diagnoses the virtual-call trap and ExceptionInInitializerError/NoClassDefFoundError chain and prescribes fixes.
Establishes coding standards (no overridable calls in ctors, exception-safe static init, no static cycles) and debugs cross-class init deadlocks.
## Background Initialization runs in a fixed order (static once at class load, parent before child; instance per-`new`, field initializers/blocks before the constructor body). Several real bugs come from code that *reads state before it is set* by that order. ## Pitfall 1: forward reference among static fields Static field initializers run in **textual order**. If an earlier one reads a later one, it sees the **default** value. ```java class Cfg { static int a = b + 1; // b not yet initialized -> b is 0 here static int b = 5; } // Cfg.a == 1, not 6 ``` Fix: declare dependencies **before** their users, or compute in a single block in the right order. ## Pitfall 2: overridable method called during construction A constructor, field initializer, or instance block that calls an **overridable** (non-final, non-private, non-static) method will dispatch to the **subclass override** while the subclass's own fields are still at defaults. ```java abstract class Base { Base() { init(); } // virtual call during construction abstract void init(); } class Impl extends Base { private final String name = "x"; void init() { System.out.println(name.length()); } // name is null here -> NPE } // new Impl() --> NullPointerException, because name's initializer runs AFTER super() returns ``` Fix: don't call overridable methods from constructors. Make such methods `final` or `private`, or pass the needed data in via the constructor. ## Pitfall 3: exception in a static initializer If a static field initializer or `static {}` block throws, the JVM wraps it in **`ExceptionInInitializerError`** and marks the class **erroneous**. The class is *never* successfully initialized; **every subsequent reference** throws **`NoClassDefFoundError`** — which hides the original cause and looks like a missing class. ```java class Bad { static int x = 1 / 0; // ArithmeticException -> ExceptionInInitializerError } // first use: ExceptionInInitializerError // later uses: NoClassDefFoundError: Could not initialize class Bad ``` Fix: keep static initializers trivial and robust; if work can fail, do it lazily and handle the exception so it doesn't escape static init. ## Pitfall 4: cyclic static dependencies between classes If A's static init uses B and B's static init uses A, whichever class triggered initialization first will, mid-cycle, see the other's statics at their **default** values (the JVM does not re-enter an in-progress initialization on the same thread). This silently yields wrong constants. Fix: break the cycle; avoid mutual static references, or move shared constants to a third class. ## Pitfall 5: relying on declaration-initializer value that the constructor overwrites `int x = 1;` in a field, then `x = 2;` in the constructor body → final value is 2, because the body runs **after** the field initializer. Not a bug per se, but a frequent source of confusion. ## How to avoid all of them - Order static (and instance) declarations so each depends only on earlier ones. - Never call overridable methods from constructors/initializers; use `final`/`private` or constructor parameters. - Keep static initializers simple, deterministic, and exception-safe; defer fallible work to lazy methods. - Avoid mutual static dependencies between classes. - Remember the constructor body runs last and can overwrite field initializers.
- Why does the second access to a class whose static initializer threw give NoClassDefFoundError instead of the original exception?The first failure throws ExceptionInInitializerError and marks the class erroneous; the JVM won't retry initialization, so every later use throws NoClassDefFoundError: Could not initialize class — the original cause appears only in the first error's stack trace.
- How do you safely run logic right after an object is fully constructed instead of in the constructor?Use a factory method or builder that creates the object and then calls an init step, or make the called method final/private so it isn't overridden; this avoids dispatching into a not-yet-initialized subclass.
saying these in an interview costs you the question
- Assuming static fields can reference each other in any order
- Calling overridable methods from constructors expecting initialized subclass state
- Letting fallible work run inside a static initializer
- Interpreting NoClassDefFoundError as a missing JAR when the real cause was a static-init exception