Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does assignment in static init block compile without error?

I was experimenting on initialization order in Java and I came across something really confusing:

static {
    System.out.println("Static 1, staticField can't be accessed (compile error)");
    staticField = "value"; // NO COMPILE ERROR!
    //System.out.println(staticField); // compile error
}

public static String staticField;

static {
    System.out.println("Static 2, staticField=" + staticField); // prints "value"
}

As you can see, we cannot reference a field that was not declared yet, hence the compile error on System.out.println(staticField); in the first static block:

Cannot reference a field before it is defined.

However, it is possible to assign such a field, as we can tell from the value in the second static block.

Why is this so?

like image 842
Joffrey Avatar asked Oct 02 '22 07:10

Joffrey


1 Answers

The behaviour is listed in 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.

It is a compile-time error if any of the four requirements above are not met.

Basically, when you are accessing a static field on its simple name on left hand side of an expression, the declaration should not be done before it, as per the second rule. However, using it on the right hand side of an assignment, or trying to use its value in an expression, then you need to declare it beforehand, else it is a compiler error.

In other words, you can assign any value to those fields, but cannot use their value on simple name, which is what you're trying to do in the print statement.

Of course, if you use the field using the qualified name, then it would work. So, the following code would compile:

static {
    System.out.println("Static 1, staticField can't be accessed (compile error)");
    staticField = "value"; // NO COMPILE ERROR!
    System.out.println(Main.staticField); // compiles fine now
}
like image 193
Rohit Jain Avatar answered Oct 05 '22 10:10

Rohit Jain