public class Main {
static int x = Main.y;
// static int x = y; //Not allowed; y is not defined
static int y = x;
public static void main(String[] args) {
System.out.println(x);//prints 0
}
}
How come I am allowed to use y trough the class, but not directly?
When is y defined?
The precise rules governing forward reference to class variables are described in the section §8.3.2.3 of the JLS:
8.3.2.3 Restrictions on the use of Fields during Initialization
The declaration of a member needs to appear textually before it is used only if the member is an instance (respectively
static
) field of a class or interface C and all of the following conditions hold:
- The usage occurs in an instance (respectively
static
) variable initializer of C or in an instance (respectivelystatic
) initializer of C.- The usage is not on the left hand side of an assignment.
- The usage is via a simple name.
- C is the innermost class or interface enclosing the usage.
A compile-time error occurs if any of the four requirements above are not met.
This means that a compile-time error results from the test program:
class Test { int i = j; // compile-time error: incorrect forward reference int j = 1; }
whereas the following example compiles without error:
class Test { Test() { k = 2; } int j = 1; int i = j; int k; }
even though the constructor (§8.8) for Test refers to the field k that is declared three lines later.
These restrictions are designed to catch, at compile time, circular or otherwise malformed initializations. Thus, both:
class Z { static int i = j + 2; static int j = 4; }
and:
class Z { static { i = j + 2; } static int i, j; static { j = 4; } }
result in compile-time errors. Accesses by methods are not checked in this way, so:
class Z { static int peek() { return j; } static int i = peek(); static int j = 1; } class Test { public static void main(String[] args) { System.out.println(Z.i); } }
produces the output:
0
because the variable initializer for i uses the class method peek to access the value of the variable j before j has been initialized by its variable initializer, at which point it still has its default value (§4.12.5).