Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the order of declarations important for static initializers?

I have this code

private static Set<String> myField;

static {
    myField = new HashSet<String>();
    myField.add("test");
}

and it works. But when I flip the order, I get an illegal forward reference error.

static {
    myField = new HashSet<String>();
    myField.add("test"); // illegal forward reference
}

private static Set<String> myField;

I'm a little bit shocked, I didn't expect something like this from Java. :)

What happens here? Why is the order of declarations important? Why does the assignment work but not the method call?

like image 409
Daniel Rikowski Avatar asked Jul 27 '09 10:07

Daniel Rikowski


People also ask

How do you declare and initialize a static variable?

Static functions can be called directly by using class name. Static variables are initialized only once. Compiler persist the variable till the end of the program. Static variable can be defined inside or outside the function.

What are static initializers and when would you use them?

A Static Initialization Block in Java is a block that runs before the main( ) method in Java. Java does not care if this block is written after the main( ) method or before the main( ) method, it will be executed before the main method( ) regardless.

What controls the initial value of the uninitialized static variables?

If the initial value of a static variable can't be evaluated at compile time, the compiler will perform zero-initialization. Hence, during static initialization all static variables are either const-initialized or zero-initialized. After static initialization, dynamic initialization takes place.

How many times static member variable is initialized?

A static variable in a block is initialized only one time, prior to program execution, whereas an auto variable that has an initializer is initialized every time it comes into existence.


1 Answers

First of all, let's discuss what a "forward reference" is and why it is bad. A forward reference is a reference to a variable that has not yet been initialized, and it is not confined only to static initalizers. These are bad simply because, if allowed, they'd give us unexpected results. Take a look at this bit of code:

public class ForwardRef {
    int a = b; // <--- Illegal forward reference
    int b = 10;
}

What should j be when this class is initialized? When a class is initialized, initializations are executed in order the first to the last encountered. Therefore, you'd expect the line

a = b; 

to execute prior to:

b = 10; 

In order to avoid this kind of problems, Java designers completely disallowed such uses of forward references.

EDIT

this behaviour is specified by section 8.3.2.3 of Java Language Specifications:

The declaration of a member needs to appear 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.

  • C is the innermost class or interface enclosing the usage.

A compile-time error occurs if any of the three requirements above are not met.

like image 93
dfa Avatar answered Dec 28 '22 11:12

dfa