How static block in java works?

Viewed 86

As far as I know, static fields and blocks are processed from top to bottom in a class. I mean, a field (static field) has to be declared before it can be used in static block. The static field must be declared first, then static block modifying that static field. Right?

Like this:

private static Map<String, Object> map = new HashMap<>();
static {
    map.put("key", "value");
}

And it compiles. And if we reverse the ordering like this:

static {
    map.put("key", "value");
}
private static Map<String, Object> map = new HashMap<>();

It fails to compile as expected.

However, if I write like this.

static {
    map = new HashMap<>();
}
private static Map<String, Object> map;

It complies successfully?! Does anybody know what's going on? It doesn't mind if I assign a new object to map, but if I put something on the map it fails to compile.

Please give me a reasonable answer.

1 Answers

The rationale for disallowing the use of map in the static initialiser is mentioned in the Java Language Specification:

§12.4.1:

The static initializers and class variable initializers are executed in textual order, and may not refer to class variables declared in the class whose declarations appear textually after the use, even though these class variables are in scope. This restriction is designed to detect, at compile time, most circular or otherwise malformed initializations.

Since the initialisers run in textual order, the static initialiser will be run before new HashMap<>(), so when map.put is executed, map would not have been initialised at that point. Clearly, this is "malformed".

On the other hand, if you did map = new HashMap<>(); in the static initialiser, you are just initialising map. Nothing is wrong there! Note that it is the variable initialisers (the things after =) that are processed from top to bottom. You can always see declarations that are declared textually ahead, as long as they are in scope. The field declaration of map is in scope in both cases.

The precise rules of what is and is not allowed is further specified in §8.3.3:

Use of class variables whose declarations appear textually after the use is sometimes restricted, even though these class variables are in scope. Specifically, it is a compile-time error if all of the following are true:

  • The declaration of a class variable in a class or interface C appears textually after a use of the class variable;

  • The use is a simple name in either a class variable initializer of C or a static initializer of C;

  • The use is not on the left hand side of an assignment;

  • C is the innermost class or interface enclosing the use.

Note the third point - it is only an error if the use is not on the LHS!

Related