Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static initializer cannot reference a field before it is defined

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.

like image 631
Andy Avatar asked Jul 16 '26 10:07

Andy


2 Answers

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.

like image 178
Radiodef Avatar answered Jul 18 '26 00:07

Radiodef


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.)

like image 39
khelwood Avatar answered Jul 17 '26 23:07

khelwood