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