3

エラーがコメントされた次のコードがあります

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 が初期化されるまでに、a はすでに初期化されているはずです。

このクラスをシングルトンとして設定するという回避策がありますが、そうするとコードが少し読みにくくなります。ここで何がうまくいかないのか知りたいです。

4

3 に答える 3

2

これは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();
}

(ただし、それを阻止してとにかくエラーを発生させる2つの方法を示しました。)

#2 は少し難解なので、#1 または #3 をお勧めします。このルールがキャッチするように設計されているエラーを作成していないようです。

于 2014-11-06T17:32:11.293 に答える
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
    }


}



    }
于 2014-11-06T16:58:20.037 に答える