Search code examples
javastatic-variablesclass-variables

How a static variable is accessible before the declaration?


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?


Solution

  • 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).