How a static variable is accessible before the declaration?

喜你入骨 提交于 2019-12-06 04:52:03

问题


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 (respectively static) 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 to Main.y, the compiler sees a reference to a class, so it will end defining x to the current value of the member y of the class Main. It treats this case as if Main 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!