Why is ad order 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 turn the order over, I get an illegal direct link error.

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

I'm a little shocked, I did not expect something like this in Java. :)

What's going on here? Why is ad order important? Why is the task executed, but not the method call?

+6
java language-features
source share
6 answers

First of all, discuss what a “direct link” is and why it is bad. A direct reference is a reference to a variable that has not yet been initialized, and it is not limited to static initializers. This is bad, because if they are allowed, they will 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 happen if this class is initialized? When a class is initialized, initializations are performed so that the first and last collide. So you expect the string

 a = b; 

to execute to:

 b = 10; 

To avoid such problems, Java developers have completely abandoned this use of advanced links.

EDIT

this behavior is indicated in section 8.3.2.3 of the Java language specifications :

An element declaration must appear before it is used only if the element is an instance (respectively static) field of a class or interface C and all of the following conditions are true:

  • Use occurs in an instance (respectively static) initializer of a variable C or in an instance (respectively static) initializer of C.

  • Use is not on the left side of the quest.

  • C is the innermost class or interface that spans usage.

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

+10
source share

try the following:

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

it should compile without errors according to JLS ...
(do not help, or?)

+2
source share

In Java, all initializers, static or otherwise, are evaluated in the order in which they appear in the class definition.

+1
source share

See the rules for direct links in JLS . You cannot use direct links if:

  • Use occurs in an instance (respectively static) initializer of a variable C or in an instance (respectively static) initializer of C.
  • Use is not on the left side of the quest.
  • Use is made using a simple name.
  • C is the innermost class or interface that spans usage.

Since all this is done for your example, the front link is illegal.

+1
source share

To find out the DFA answer:

I think you turned off the "left side" rule at the second token point in JLS 8.2.3.2. In your initialization, myField is on the left. In your call to add, this is on the right side. The code here is implicit:

 boolean result = myField.add('test') 

You do not evaluate the result, but the compiler still acts as if it were. This is why your initialization passes when your add () call fails.

As to why this is so, I have no idea. This may well be for the convenience of JVM developers, as far as I know.

+1
source share

I think the method call is problematic because the compiler cannot determine which add() method to use without the reference type for myField .

At run time, the method used will be determined by the type of the object, but the compiler only knows about the reference type.

0
source share

All Articles