First , let's see what JLS have to say for illegal forward references.
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.
Use of instance variables whose declarations appear textually after
the use is sometimes restricted, even though these instance variables
are in scope. Specifically, it is a compile-time error if all of the
following are true:
The declaration of an instance variable in a class or interface C
appears textually after a use of the instance variable;
The use is a simple name in either an instance variable initializer of
C or an instance 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.
It defines what is a illegal forward reference for each - static and instance variables. However, definition seems to be same for both of them. Since your question asks about static, we will dig deep into this only.
1) See, for a static variable, there is declaration
and there is initialization
.
static int a; //only declaration
static int b = 10; //both declaration and initialization
2) Use of class variables whose declarations appear textually after the use is sometimes restricted, even though these class variables are in scope.
What does it explains to us ? It says that there are cases when we can use static variables even if we declare them afterwards. And in some cases this wont be allowed. So, what are the cases that this won't be allowed ?
If the following 4 conditions are true at the same time. Else you are free to use it even though you have declared it afterwards.
a) The declaration of a class variable in a class or interface C appears textually after a use of the class variable;
b) The use is a simple name in either a class variable initializer of C or a static initializer of C;
c) The use is not on the left hand side of an assignment;
d) C is the innermost class or interface enclosing the use.
Well, the a)
point is simple. It says that you must be looking at these rules only when you want to use a static variable before declaring it else why would you dig up into this JLS.
The b)
point is that if you use simple name like boy
[and not class name appended to it like MyClass.boy
only then you might
enter the problem of illegal forward reference else you are safe my friend. But just this condition don't qualifies for Illegal forward reference else your a=99
in you code would have given us error immediately. There are 2 more conditions that HAVE to be true for this error to generate . If the below 2 does not qualify, you are allowed to use it like this.]
The point c)
is pretty straightforward. Are you not using in left hand side of assignment ? If we look at a=99
, Nope !! System.out.println(a)
- This is not even an assignment. Hence no left hand assignment is true.
The point d)
is also simple. It just tell you which class/Interface C he means in definition.Your C = Test.
Now let's revisit your code. At each line of code, I will comment True+False+True+false
something like this meaning that for each line what point a), b) , c) ,d) will give to each of line. Okay ?
class Test {
static {
System.out.println(a); // True + True + True +True ; Illegal forward reference
a = 99; // True + True + False +True ; No illegal forward reference
System.out.println(Test.a); // True + False + True + True No illegal forward reference
}
static int a = 10;
static {
System.out.println(a);
}
}
The next question one may think is now what it will print ? What values will it take if we use before declaring it ?
Now we come to rules of static initialization. Here, we will go according to your code.
When class is loaded and no illegal forward reference is not there , all the static variables have been initialized to default value and are present in memory.
Now, after this static initialization takes place.
class Test {
static {
System.out.println(Test.a); // prints 0
a = 99; // a get 99
System.out.println(Test.a); // prints 99
}
static int a = 10;
static {
System.out.println(a); // prints 10
}
public static void main(String[] args) {
}
}