What are instance initializer blocks and static initializer blocks, and how do they relate to scope and initialization order?
answer
- Instance init: bare { } in class body, runs per object
- Static init: static { }, runs once at class init
- Both interleave with field initializers in textual order
- Vars declared inside are block-local
- Static block sees only static members (no this)
basics
~20 sBesides ordinary blocks, a class can have a bare { } block (instance initializer) that runs when an object is created, and a static { } block that runs once when the class is loaded. Variables you declare inside these blocks are local to the block, but they can read and set the class's fields.
solid answer
~50 sA class body may contain two special kinds of blocks. An instance initializer block is a bare { } directly in the class body; its code runs for every new instance, after the superclass constructor and before the constructor body, in textual order with field initializers. A static initializer block, written static { }, runs exactly once when the class is initialized (loaded and prepared for first use), again interleaved with static field initializers in textual order. Both are full blocks, so any variable declared inside is block-local and invisible outside, but the block can read and assign the enclosing class's instance or static fields respectively. A static block sees only static members; an instance block sees both. They are useful for initialization logic too complex for a single field initializer expression, such as populating a static map or validating environment state.
code
java · 17 linesclass Config {
static final Map<String, String> DEFAULTS = new HashMap<>();
static { // runs once at class init
int v = computeVersion(); // v is local to this block
DEFAULTS.put("version", String.valueOf(v));
}
int id;
{ id = nextId(); } // instance initializer: runs per object, before ctor body
Config() { /* id already set here */ }
static int computeVersion() { return 7; }
static int counter = 0;
static int nextId() { return ++counter; }
}go deeper
Recognizes that static { } and a bare { } in a class body are special initializer blocks, not methods.
Knows static runs once at class load, instance runs per object, both in textual order with field initializers, and that inner declarations are block-local.
Explains full construction order across superclass/subclass, the static-vs-instance member access rules, and forward-reference restrictions.
Reasons about class-initialization timing/laziness, ExceptionInInitializerError, anti-patterns like double-brace init, and when to prefer constructors/factories over initializer blocks for testability and clarity.
## Two special class-body blocks Most blocks are method bodies or control-statement bodies. But a **class body** can directly contain two more kinds of block: ### 1. Instance initializer block A bare `{ ... }` placed directly inside the class (not inside a method): ```java class Account { int balance; { balance = 100; } // instance initializer } ``` Its code runs **every time an instance is created**. The order for object construction is: superclass constructor runs first, then the subclass's **instance field initializers and instance initializer blocks run in the order they appear in the source**, and finally the rest of the constructor body. So instance initializers are a way to share setup code across multiple constructors. ### 2. Static initializer block A block prefixed with `static`: ```java class Config { static final Map<String,String> M = new HashMap<>(); static { M.put("k", "v"); } // static initializer } ``` It runs **exactly once**, when the class is **initialized** — that is, the first time the class is actively used (first instance created, first static member accessed, etc.). Static field initializers and static blocks run **in textual order**. ## Scope inside these blocks Both are ordinary blocks for scoping purposes. A variable you **declare** inside is **block-local** — visible only within that block, gone at its closing brace: ```java static { int tmp = compute(); // local to this static block M.put("x", "" + tmp); } // tmp is not visible here ``` But the block can **reach the class's fields**: - A **static** block can access only **static** members (there is no instance yet). - An **instance** block can access both **instance and static** members. Referring to an instance field from a static block is a compile error, because no `this` exists during class initialization. ## Initialization order, end to end For a fresh object of a subclass, roughly: 1. Class initialization (if not already done): superclass static init, then this class's static field initializers + static blocks in textual order — **once ever**. 2. Object creation: allocate, default-zero all fields, run superclass constructor, then this class's **instance field initializers + instance blocks in textual order**, then the constructor body. ## Forward-reference subtlety Within these blocks you generally cannot *read* a field declared textually *later* before it's initialized (the 'illegal forward reference' rule), though you may assign it. This ties initialization order to source order. ## When to use them - **Static block:** one-time setup of static state that needs more than a single expression (build a lookup map, load a native library, read config). - **Instance block:** shared instance setup common to all constructors (less common than just calling a private init method, but valid). ## Pitfalls - Overusing instance initializer blocks hurts readability; a constructor or a field initializer is usually clearer. - The 'double-brace initialization' idiom (`new HashMap<>() {{ put(...); }}`) is an anonymous subclass with an instance initializer — it leaks an extra class and an outer reference, and is generally discouraged. - A static block throwing an exception causes an ExceptionInInitializerError and the class fails to initialize.
- When exactly does a static initializer block run?Once, at class initialization — the first active use of the class (first instance, first static member access, etc.) — interleaved with static field initializers in source order.
- Why can't a static block reference an instance field directly?Class initialization happens before any instance exists, so there is no this to qualify the instance field; it is a compile error.
saying these in an interview costs you the question
- Thinking a static block runs once per instance
- Accessing an instance field from a static block
- Confusing instance initializer (every object) with static (once)
- Recommending double-brace initialization as a clean idiom
- Believing constructor body runs before instance initializer blocks