问题
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?
回答1:
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).
回答2:
I would assume that by using the class, the compiler would defer looking for the variable until the class was complete, so it finds y, but if you just define it like the comment it is not yet defined so it fails
回答3:
Static variables are defined in order of declaration in the class, during class loading. When the JVM will load the Main
class, x
will be defined, then y
. That's why you can't directly use y
when initializing x
, you create something that's called a forward reference, you refers to a variable not currently defined, and that's illegal for the compiler.
When using Main.y
, I think the following happens:
- You load
Main
,x
initialization is called - When you define
x
to be equals toMain.y
, the compiler sees a reference to a class, so it will end definingx
to the current value of the membery
of the classMain
. It treats this case as ifMain
was a different class.
Note that in this case, when initializing x
, y
hasn't be defined for the moment. So x
will have a value of 0
.
回答4:
You're not permitted to do it because it is meaningless. The only possible interpretation is that y is initialized to zero, and you already have two ways of saying that. You don't need this.
回答5:
Perhaps the compiler creates the references of the static variables with default values with the class in the stack, when it's created and then assigns the provided values.
来源:https://stackoverflow.com/questions/3699010/how-a-static-variable-is-accessible-before-the-declaration