web-dev-qa-db-ja.com

Java?

プロジェクトに複数のクラスが含まれており、各クラスに静的初期化ブロックがあるとします。これらのブロックはどの順序で実行されますか?クラス内では、そのようなブロックはコードに現れる順序で実行されることを知っています。クラス間で同じであることを読みましたが、私が書いたいくつかのサンプルコードはこれに同意しません。私はこのコードを使用しました:

package pkg;

public class LoadTest {
    public static void main(String[] args) {
        System.out.println("START");
        new Child();
        System.out.println("END");
    }
}

class Parent extends Grandparent {
    // Instance init block
    {
        System.out.println("instance - parent");
    }

    // Constructor
    public Parent() {
        System.out.println("constructor - parent");
    }

    // Static init block
    static {
        System.out.println("static - parent");
    }
}

class Grandparent {
    // Static init block
    static {
        System.out.println("static - grandparent");
    }

    // Instance init block
    {
        System.out.println("instance - grandparent");
    }

    // Constructor
    public Grandparent() {
        System.out.println("constructor - grandparent");
    }
}

class Child extends Parent {
    // Constructor
    public Child() {
        System.out.println("constructor - child");
    }

    // Static init block
    static {
        System.out.println("static - child");
    }

    // Instance init block
    {
        System.out.println("instance - child");
    }
}

そして、この出力を得ました:

開始
static-祖父母
static-親
static-子供
インスタンス-祖父母
constructor-祖父母
インスタンス-親
constructor-parent
インスタンス-子
constructor-子供
終わり

それからの明らかな答えは、親のブロックが子供のブロックの前に実行されることですが、それは偶然かもしれず、2つのクラスが同じ階層にない場合は役に立ちません。

編集:

これをLoadTest.Javaに追加して、サンプルコードを変更しました。

class IAmAClassThatIsNeverUsed {
    // Constructor
    public IAmAClassThatIsNeverUsed() {
        System.out.println("constructor - IAACTINU");
    }

    // Instance init block
    {
        System.out.println("instance - IAACTINU");
    }

    // Static init block
    static {
        System.out.println("static - IAACTINU");
    }
}

クラス名が示すように、新しいクラスをどこでも参照したことはありません。新しいプログラムは、古いプログラムと同じ出力を生成しました。

91
Pops

クラスの静的初期化子は、インスタンスを作成するため、または静的メソッドまたは静的フィールドにアクセスするために、クラスが最初にアクセスされたときに実行されます。

したがって、複数のクラスの場合、これらのクラスをロードするために実行されるコードに完全に依存します。

60

JLSバージョン8 のセクション12.4および12.5を参照してください。これらすべてについて詳細に説明します(静的の場合は12.4、インスタンス変数の場合は12.5)。

静的初期化の場合(セクション12.4):

クラスまたはインターフェイスタイプTは、次のいずれかが最初に発生する直前に初期化されます。

  • Tはクラスであり、Tのインスタンスが作成されます。
  • Tはクラスであり、Tによって宣言された静的メソッドが呼び出されます。
  • Tによって宣言された静的フィールドが割り当てられます。
  • Tによって宣言された静的フィールドが使用され、そのフィールドは定数変数ではありません(4.12.4)。
  • Tはトップレベルクラス(§7.6)であり、T(§8.1.3)内で字句的にネストされたassertステートメント(§14.10)が実行されます。

(およびいくつかのイタチ語句)

92
Keith Randall

キースとクリスの答えはどちらも素晴らしいです。特定の質問にさらに詳細を追加するだけです。

静的初期化ブロックは、クラスが初期化される順序で実行されます。では、それはどのような順序ですか? JLS 12.4.1に準拠:

クラスまたはインターフェイスタイプTは、次のいずれかが最初に発生する直前に初期化されます。

  • Tはクラスであり、Tのインスタンスが作成されます。
  • Tはクラスであり、Tによって宣言された静的メソッドが呼び出されます。
  • Tによって宣言された静的フィールドが割り当てられます。
  • Tによって宣言された静的フィールドが使用され、そのフィールドは定数変数ではありません(4.12.4)。
  • Tは最上位クラスであり、T内で字句的にネストされたassertステートメント(§14.10)が実行されます。

クラスClassおよびパッケージJava.lang.reflectの特定のリフレクトメソッドを呼び出すと、クラスまたはインターフェイスの初期化も行われます。クラスまたはインターフェイスは、他の状況では初期化されません。

例として、この例で何が起きているかを説明します。

  1. メインに入る
  2. 「START」を印刷
  3. Childの初期化が必要なChildの最初のインスタンスを作成しようとしています
  4. 子を初期化しようとすると、親が初期化されます
  5. Parentを初期化しようとすると、Grandparentが初期化されます
  6. 祖父母の初期化の開始時に、祖父母の静的初期化ブロックが実行されます
  7. 技術的には、オブジェクトは祖父母の親であるために初期化チェーンの最後の発言権を得ますが、貢献するものは何もありません
  8. 祖父母の静的初期化ブロックが終了すると、プログラムは親の静的初期化ブロックにフォールバックします
  9. 親の静的初期化ブロックが終了すると、プログラムは子の静的初期化ブロックにフォールバックします
  10. この時点で、Childは初期化されるため、そのコンストラクタは続行できます
  11. IAmAClassThatIsNeverUsedは参照されないため、静的初期化ブロックを含むコードは実行されません
  12. このチュートリアルの残りの部分は、静的初期化子には関係なく、完全を期すためにのみ含まれています。
  13. 子のコンストラクターは暗黙的にsuper()を呼び出します(つまり、親のコンストラクター)
  14. 親のコンストラクターは暗黙的にsuper()を呼び出します(つまり、祖父母のコンストラクター)
  15. 祖父母のコンストラクターも同じことを行いますが、効果はありません(繰り返しますが、オブジェクトには何も貢献しません)
  16. 祖父母のコンストラクタのsuper()の呼び出しの直後に、祖父母のインスタンス初期化ブロックが来る
  17. 祖父母のコンストラクターの残りのコンストラクターが実行され、コンストラクターが終了します
  18. プログラムは、super()(つまり、Grandparentのコンストラクター)の呼び出しが解決した直後に、Parentのコンストラクターにフォールバックします
  19. 上記のように、Parentのインスタンス初期化子が処理を行い、コンストラクターが終了します
  20. 同様に、プログラムはChildのコンストラクタに戻り、それを完了します
  21. この時点で、オブジェクトはインスタンス化されています
  22. 「END」を印刷
  23. 正常終了
32
Pops

クラスの初期化は、静的イニシャライザーと、クラスで宣言された静的フィールド(クラス変数)のイニシャライザーの実行で構成されます。

インターフェースの初期化は、インターフェースで宣言されたフィールド(定数)の初期化子の実行で構成されます。

クラスを初期化する前に、その直接のスーパークラスを初期化する必要がありますが、クラスによって実装されるインターフェースは初期化されません。同様に、インターフェイスが初期化される前に、インターフェイスのスーパーインターフェイスは初期化されません。

1
Bala

http://docs.Oracle.com/javase/tutorial/Java/javaOO/initial.html

Java documentation。

静的ブロックがどのように存在しても、それらが現れる順序で単一ブロックとして実行されることを明確に述べました

そう、

ここでの私の理解はJavaはあなたのコードを

static{
i=1;
i=2;
}

static int i;

それがあなたが出力2を得ている理由です

これがお役に立てば幸いです

0
Avinash Perla

静的ブロックが呼び出されない場合が1つあります。

class Super {
    public static int i=10;
}
class Sub extends Super {
    static {
        system.out.println("Static block called");
    }
}
class Test {
    public static void main (String [] args) {
        system.out.println(Sub.i);
    } 
}

上記のコードは10を出力します

0
Java Main
class A {
  public A() { 
    // 2
  }
}

class B extends A{
  static char x = 'x'; // 0
  char y = 'y'; // 3
  public B() { 
    // 4
  }

  public static void main(String[] args) {
    new B(); // 1
  }
}

コメント内の数字は、評価順序を示し、小さいほど早くなります。

例が示したように、

  1. 静的変数
  2. メイン
  3. スーパークラスのコンストラクター
  4. インスタンス変数
  5. コンストラクタ
0
GraceMeng

同じクラスに複数の静的イニシャライザとインスタンスイニシャライザを設定できます。したがって、

  • 静的初期化子は、宣言されたテキストの順序で呼び出されます( 12.4.2 から)
  • インスタンス初期化子は、宣言されたテキストの順序で呼び出されます( 12.5 から)

それぞれが単一のブロックであるかのように実行されます。

0
Martin Tapp