The rules for forward reference is defined in JLS §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 (§6.3). 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.
So, basically your first Sysout()
, satisfies all the above 4 conditions, and hence it's a compile time error.
In the 2nd Sysout()
, you're accessing a
using it's qualified name, rather than simple name, which as per the above rules is allowed.
Now, the reason for this would be, when you access Test.a
, the compiler is sure that Test
class has been loaded and all static
fields have been initialized, so it can access the field a
. But while accessing a
on simple name, the compiler isn't sure that initializer for a
has already run or not, since it might still be in process of loading the class.
Consider the following process of loading of class:
- When a class is loaded, memory is allocated for all the
static
variables declared in it. At this point, the variable a
has got its memory allocated (declaration done)
- Then all the
static
initializers run in the order of occurrence.
- First statement is
Sysout(a);
. a
hasn't been initialized yet, so you can't access it. (error)
- Second statement is
a = 99
. Here you're actually initializing the variable a
. Perfectly fine.
- Third one is
Sysout(Test.a)
- reasoning for this is already posted above. Compiler knows Test
is already loaded.
- Then
static int a = 10
is executed. It re-initializes a
to 10
. Remember, declaration part is already taken care of in first step.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…