You can see what the scope of any declaration is, by reading section 6.3 of the Java Language Specification.
In particular,
The scope of a declaration of a member m declared in or inherited by a class or interface C
is the entire body of C
, including any nested class or interface declarations.
So the scope of a
is the entire body of testStatic
. The static initialiser is in the body of testStatic
, so a
is in scope in the body of the static initialiser.
No additional restrictions regarding whether a
is accessible, or whether you can set it applies here, so a = 2;
compiles.
In a sense, this works for the same reason that calling a method before it is declared works:
void f() {
g(); // can call g here!
}
void g() {}
Note that this is different in the case of referring to other static fields in the field initialiser of a static field. i.e. this does not compile:
class Foo {
static int b = a; // changing this to Foo.a works
static int a = 0;
}
Even though a
is in scope in the field initialiser of b
, this is now allowed in the specification, section 8.3.3:
For a reference by simple name to a class variable f declared in class
or interface C, it is a compile-time error if:
The reference appears either in a class variable initializer of C or
in a static initializer of C (§8.7); and
The reference appears either in the initializer of f's own declarator
or at a point to the left of f's declarator; and
The reference is not on the left hand side of an assignment expression
(§15.26); and
The innermost class or interface enclosing the reference is C.
Also note that the scope of local variables does not include the code before it is declared:
The scope of a local variable declared in a block by a local variable declaration statement (§14.4.2) is the rest of the block, starting with the declaration's own initializer and including any further declarators to the right in the local variable declaration statement.
Note the wording of "the rest of the block".