我有以下代码,错误已注释
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;
}
我对使用静态初始化器相当新,但我不知道为什么不能编译。我查看了有关此主题的一些帖子,并看到了初始化运行的顺序,但这似乎没有违反规则。到b初始化时,应该已经有了。
我有一个解决方法,就是将这个类设置为单例,但这样做会使代码的可读性降低一些。我很想知道这里出了什么问题。
答案 0 :(得分:2)
如果尚未声明静态块,则无法使用a
。所以在静态块之前声明它:
public final class MyStaticClass {
private MyStaticClass() {}
private static final A a;
private static final B b;
static {
a = new A();
b = new B(a);
}
}
(我假设您调用A
" b"以及B
" a"的实例是一个错字。)
答案 1 :(得分:1)
静态初始化按照在代码中编写的顺序完成。因此,在您的代码中,它将首先进入静态块,然后将转到变量声明...
你不能在声明之前使用变量,这就是为什么它不会编译......
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
}
}
}
答案 2 :(得分:1)
JLS 8.3.3中对此进行了解释。事实上,有几种方法可以解决它。
使用限定名称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;
}
如果a
和b
是在实例初始值设定项中初始化的实例字段,则a
可以被限定为this.a
。
将a
的前向引用放在作业的左侧:
// #2
public final class MyStaticClass {
static {
b = new B(a = new A());
}
private static final A a;
private static final B b;
}
当然,在参考文献之前以文字形式提出声明:
// #3
public final class MyStaticClass {
private static final A a;
private static final B b;
static {
a = new A();
b = new B(a);
}
}
根据JLS,#3在技术上并不是必需的("这些类变量在范围内" ),而是设计用于捕获字段中的特定类型的错误无序初始化:
public final class MyStaticClass {
private static final B b = new B(a); // a is null
private static final A a = new A();
}
(虽然我只是告诉你两种方法来阻止它并且无论如何都要犯错误。)
我推荐#1或#3,因为#2有点深奥。您似乎没有犯这个规则旨在捕获的错误。