25

私は2つのクラスを持っています:

クラスA:

public class A {
    static B b = new B();

     static {
         System.out.println("A static block");
     }

     public A() {
         System.out.println("A constructor");
     }
}

クラス B:

public class B {
     static {
         System.out.println("B static block");
         new A();
     }

     public B() {
         System.out.println("B constructor");
     }
}

新しい A を作成するだけの Main クラスを作成します。

public class Main {
    public static void main(String[] args) {
        new A();
    }
}

私が得る出力は次のとおりです。

B static block
A constructor
B constructor
A static block
A constructor

ご覧のとおり、 A のコンストラクターは静的初期化子の前に呼び出されます。

私が作成した循環依存関係と関係があることは理解していますが、静的初期化子は常にコンストラクターの前に実行する必要があるという印象を受けました。

これが発生する理由は何ですか (技術的には Java 実装で) ?

静的初期化子をまとめて避けることをお勧めしますか?

4

1 に答える 1

25
static B b = new B();

前です

static {
     System.out.println("A static block");
}

したがって、印刷する前に B インスタンスを初期化する必要があります"A static block"

B クラスを初期化すると、A インスタンスを作成する必要があります。したがって、A インスタンスが構築される前に「A static block」を出力する方法はありません。

はい、コンストラクターが起動される前に A の静的初期化が起動されますが、デッドロックを除けば、必要なシーケンスに対する他の解決策はありません。

仕様の警告に注意してください。

Java プログラミング言語はマルチスレッドであるため、他のスレッドが同じクラスまたはインターフェースを同時に初期化しようとする可能性があるため、クラスまたはインターフェースの初期化には慎重な同期が必要です。クラスまたはインターフェースの初期化の一部として、そのクラスまたはインターフェースの初期化が再帰的に要求される可能性もあります。たとえば、クラス A の変数イニシャライザは、関連のないクラス B のメソッドを呼び出し、クラス A のメソッドを呼び出す可能性があります。Java 仮想マシンの実装は、次の手順 [ドキュメントは完全な手順に続きます]

Java のベスト プラクティスは、他の言語と同様に、基本的に循環依存を回避することです。循環依存の解決を予測するのは非常に困難な場合があるからです。

于 2012-12-19T08:30:22.210 に答える