Static initializer cannot reference a field before

2019-05-22 18:02发布

问题:

I have the following code with the error commented

public final class MyStaticClass {

    private MyStaticClass() {}

    static {

        a = new A();
        b = new B(a);    // Cannot access a field before it is defined
    }

    private static final A a;
    private static final B b;
}

I'm fairly new to using static initializers, but I have no idea why this will not compile. I've looked around a few of the posts on this topic, and have seen the order that initialisation runs, but this doesn't seem to violate the rule. By the time b is being initialized, a should already have been.

I have a work around, which would be to set up this class as a singleton, but doing so would make the code a little less readable. I'm keen to know what is going wrong here.

回答1:

This is explained in JLS 8.3.3. In fact, there are a few ways to fix it.

Use a qualified name of a:

// #1
public final class MyStaticClass {
    static {
        a = new A();
        b = new B(MyStaticClass.a);
    }

    private static final A a;
    private static final B b;
}

If a and b were instance fields being initialized in an instance initializer, a could be qualified as this.a.

Put the forward reference to a on the left-hand of an assignment:

// #2
public final class MyStaticClass {
    static {
        b = new B(a = new A());
    }

    private static final A a;
    private static final B b;
}

And of course put the declaration textually before the reference:

// #3
public final class MyStaticClass {
    private static final A a;
    private static final B b;

    static {
        a = new A();
        b = new B(a);
    }
}

According to the JLS, #3 is not technically necessary ("these class variables are in scope"), rather this is designed to catch a particular kind of error where fields are initialized out of order:

public final class MyStaticClass {
    private static final B b = new B(a); // a is null
    private static final A a = new A();
}

(Though I just showed you two ways to thwart it and make the error anyway.)

I'd recommend #1 or #3 since #2 is a bit esoteric. You don't seem to be making the error this rule is designed to catch.



回答2:

You can't use a in your static block when it hasn't been declared yet. So declare it before the static block:

public final class MyStaticClass {

    private MyStaticClass() {}

    private static final A a;
    private static final B b;

    static {
        a = new A();
        b = new B(a);
    }

}

(I assumed that calling your instance of A "b" and your instance of B "a" was a typo.)



回答3:

Static initialization is done in the order it's written in the code. So in your code it will enter the static block first and then will go to the variable declaration...

you cant use a variable before it is declared and thats why it wont compile...

public final class MyStaticClass {

       private static final A a;
        private static final B b;

    private MyStaticClass() {}

    static {

        a =  new A();
        b = new B(a);    // Cannot access a field before it is defined
    }


}



    }