What exactly triggers a class's static initializer to run, and what does NOT trigger it?
answer
- Triggers: new, static method call, non-constant static field access, Class.forName(name)
- Superclass inits before subclass; default-method interface inits with impl class
- Constant static final = inlined → no init
- Declaring a var / making an array → no init
- forName(name, false, loader) loads but doesn't init
basics
~20 sStatic blocks run when the class is first actively used: creating an object, calling a static method, or reading/writing a normal static field. Just declaring a variable of the type, or reading a compile-time constant, does NOT trigger it.
solid answer
~50 sClass initialization (which runs the static blocks and field initializers) is lazy and fires on the first **active use** of the class. The active uses are: instantiating it (`new`), invoking one of its static methods, accessing or assigning a non-constant static field, and reflective initialization (e.g. `Class.forName(name)` with default flags). Initialization of a class also forces its superclass to initialize first; for an interface with default methods, initializing an implementing class triggers that interface too. Crucially, several things do **not** trigger it: declaring a reference variable of the type, referencing a `static final` **compile-time constant** (the compiler inlines the literal, so the class is never touched), accessing a static field through a subclass when the field is declared in the parent (only the parent initializes), and loading the class without using it (`Class.forName(name, false, loader)`). These rules explain many 'why didn't my static block run?' surprises.
go deeper
Knows the block runs 'the first time you use the class' and that creating an object triggers it.
Lists the main triggers (new, static method, static field) and knows initialization is lazy and once.
Enumerates the full active-use set including reflection and superclass propagation, and explains the compile-time-constant inlining exception precisely.
Reasons about loading-vs-linking-vs-init stages, classloader scoping, default-method interface initialization, and why depending on static-block side effects is a fragile design.
## Loading vs. linking vs. initialization The JVM brings a class to life in stages: **loading** (read bytecode), **linking** (verify, prepare static fields to default values, resolve), and **initialization** (run the static initializers — field assignments and `static { }` blocks). Your static blocks run only in the **initialization** stage, and that stage is **lazy** — it happens the first time the class is *actively used*, not when it's merely loaded. ## What counts as 'active use' (triggers initialization) The Java Language Specification lists these triggers: 1. **Creating an instance** — `new Foo()`. 2. **Invoking a static method** declared by the class — `Foo.doThing()`. 3. **Accessing or assigning a non-constant static field** declared by the class — `Foo.counter` or `Foo.counter = 1` (where `counter` is not a compile-time constant). 4. **Reflective triggers** — `Class.forName("Foo")` (the 1-arg form initializes by default), `clazz.newInstance()` / `getDeclaredConstructor().newInstance()`. 5. **Initializing a subclass** forces the **superclass** to initialize first. 6. For interfaces: initializing a class **initializes the interface** if the interface declares a **default method**. Whenever any of these happens for the first time, the JVM runs that class's static initializers exactly once (and serializes concurrent attempts so it's thread-safe). ## What does NOT trigger initialization (the surprises) - **Declaring a variable** of the type: `Foo f;` or `Foo[] arr = new Foo[10];` — creating an *array* of `Foo` does not initialize `Foo` (no `Foo` instance is made). - **Compile-time constants**: a `static final` field whose value is a constant expression (e.g. `static final int MAX = 100;` or a constant `String`) is **inlined by the compiler** at the use site. Reading `Foo.MAX` copies the literal into your bytecode, so `Foo` is never referenced at runtime and its static block does **not** run. (If the field is `static final` but assigned a *non*-constant expression — say `= computeMax()` — it is **not** a compile-time constant and **does** trigger init.) - **Accessing an inherited static field via a subclass**: if `Child extends Parent` and the static field lives in `Parent`, `Child.field` only initializes `Parent`, not `Child` — the field is a member of `Parent`. - **Loading without initializing**: `Class.forName(name, false, loader)` loads but explicitly defers initialization. ## A worked example of the constant trap ```java class Holder { static final int A = 10; // compile-time constant static final int B = compute(); // NOT a constant (method call) static int compute() { return 20; } static { System.out.println("init"); } } System.out.println(Holder.A); // prints 10, does NOT print "init" System.out.println(Holder.B); // prints "init" then 20 ``` Reading `A` is satisfied at compile time; reading `B` requires the class, so initialization runs and the block prints. ## Why this matters in practice Developers register JDBC drivers, set up logging, or build caches in static blocks and then wonder why the block 'didn't run.' Almost always it's one of the non-triggers above — usually constant inlining or just never actively using the class. The fix is to ensure a genuine active use (or use `Class.forName(name)` to force initialization explicitly). Conversely, relying on static-block side effects for critical setup is fragile precisely because the trigger is so easy to miss.
- Why doesn't reading a `static final int MAX = 100;` constant run the class's static block?Because it's a compile-time constant: the compiler inlines the literal 100 at the use site, so the class is never referenced at runtime and is never initialized.
- How do you force a class to initialize without creating an instance?Call `Class.forName("FullyQualifiedName")` (the one-arg form initializes by default), or trigger any active use such as invoking a static method.
saying these in an interview costs you the question
- Saying every reference to the class triggers initialization (constants and mere declarations don't)
- Believing accessing an inherited static field via a subclass initializes the subclass
- Thinking creating an array of the type instantiates/initializes the element class
- Assuming class loading and class initialization are the same event