静态初始化程序在定义之前无法引用字段

时间:2014-11-06 16:50:08

标签: java static-initialization static-initializer

我有以下代码,错误已注释

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初始化时,应该已经有了。

我有一个解决方法,就是将这个类设置为单例,但这样做会使代码的可读性降低一些。我很想知道这里出了什么问题。

3 个答案:

答案 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;
}

如果ab是在实例初始值设定项中初始化的实例字段,则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有点深奥。您似乎没有犯这个规则旨在捕获的错误。