How the order of execution is performed between static variables and blocks?

Consider the below scenario: Code:1

public class StaticDemo {
    static{
        b=5;
        System.out.println("Static B:"+b);/*Compilation error:"Cannot reference a field before it is defined"*/
    }
    static int b;
    static{
        System.out.println("B:"+b);
    }
    public static void main(String[] args) {    
    }
}

Commenting the code as below, there are no errors and following output has been displayed. Code:2

public class StaticDemo {
    static{
        b=5;
        //System.out.println("Static B:"+b);
    }
    static int b;
    static{
        System.out.println("B:"+b);
    }
    public static void main(String[] args) {    
    }
}

Output-

B:5

If the execution is based on the order in which static variables or blocks have been written.

  1. why compilation error is not thrown for the initialization (b=5) as shown in Code:2.

  2. And also please explain why error is been thrown for Code:1, if Code:2 is true?

Answers


From the Java Language Specification §8.3.2.3

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.

[...]

The restrictions above are designed to catch, at compile time, circular or otherwise malformed initializations

In other words, it's OK to write to a field that is declared later in the class, but not to read from it.

There are more detailed examples of this in the example box immediately following the section I have quoted.


In the first example, the variable b gets initialized by the first static block, which is the first one to be executed. The compiler does not remember the first line, hence in the second line of the static block, it complains to refer to b, because 'b' could be not yet initialized.

When the compiler has passed the definition of b, he is sure b is initialized. Hence your code is allowed to refer / access it.

Initializing a static variable before it occurred in the source code is fine, but accessing it is allowed only after it occurred.

If you consult the Java Specification it states the following:

Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class. 

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
    1) A static field declared by T is assigned.
    2) A static field declared by T is used and the field is not a constant variable (§4.12.4).

1) Says, that a static initializer is executed before assigning static fields directly. 2) Says, before you may use a field, the initializers (blocks and field initializer) must have been executed.

Therefore you are able to assign a value to a static field in a static initializer block, but can't use it before all initialization is done. That's how I do understand it.


The order of execution is from top to bottom. You cannot use a static field before it is declared.

why error is been thrown for Code:1, if Code:2 is true

You attempted to use a variable before it was declared. BTW not error was thrown at runtime. This is a compiler error.


Need Your Help

How to get rid of cygwin's path prefix

bash path cygwin cygpath

In cygwin, in order to remove /cydrive prefix in the paths, I did a mount like this -