final variable initialized first

Mohammad Karmi :

I was reading the question here : Java : in what order are static final fields initialized?

According to the answer

"except that final class variables and fields of interfaces whose values are compile-time constants are initialized first ..."

I think this is not correct because the following will fail :

static {
    String y = x;
}

public static final String x = "test";

In the static block, x is not recognized. Can anyone please comment if that answer is correct ?

T.J. Crowder :

The order of initialization doesn't change the fact that the JLS doesn't let you refer to variables before they're declared in various cases. This is described in JLS§8.3.3:

Use of class variables whose declarations appear textually after the use is sometimes restricted, even though these class variables are in scope (§6.3). Specifically, it is a compile-time error if all of the following are true:

  • The declaration of a class variable in a class or interface C appears textually after a use of the class variable;

  • The use is a simple name in either a class variable initializer of C or a static initializer of C;

  • The use is not on the left hand side of an assignment;

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

That's why your code gets this compilation erorr:

error: illegal forward reference

The statement that static fields that are constant variables are initialized first is indeed defined in JLS§12.4.2:

  1. Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC.

    Then, initialize the static fields of C which are constant variables (§4.12.4, §8.3.2, §9.3.1).

...

  1. Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.

As you can see, constant variables are initialized in step 6, but others in step 9.

This demonstrates the behavior:

public class Example {
    static String y;
    static  {
         y = foo();
    }

    static String foo() {
        return x.toUpperCase();
    }

    public static final String x = "test";

    public static void main(String[] args) throws Exception {
        System.out.println(x);
        System.out.println(y);
    }
}

That compiles, and outputs:

test
TEST

In contast, if you change the x line so it's not constant anymore:

public static final String x = Math.random() < 0.5 ? "test" : "ing";

It compiles, but then fails because x is null as of y = foo();.


For the avoidance of doubt: I don't recommend using methods to initialize fields like that. :-)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=125434&siteId=1