12

重複の可能性:
Java 静的クラスの初期化
は、クラス内の静的ブロックと静的変数が実行される順序は?

このコードを実行すると、答えは 1 で、2 になると思いました。初期化の順序と各ステップの k の値は何ですか?

public class Test {

    static {k = 2;}
    static int k = 1;

    public static void main(String[] args) {
        System.out.println(k);
    }
}

編集1:「kはデフォルト値に設定されています」のフォローアップとして、なぜこの次のコードがコンパイルされないのですか? 「定義する前にフィールドを参照できません」というエラーが表示されます。

public class Test {

    static {System.out.println(k);}
    static int k=1;

    public static void main(String[] args) {
        System.out.println(k);
    }
}

編集2:私にはわからない理由で、「k」の代わりに「Test.k」の場合に機能します。

すべての答えをありがとう。これで十分です:D

4

2 に答える 2

9

これらは、記述した順序で実行されます。コードが次の場合:

public class Test {

    static int k = 1;
    static {k = 2;}

    public static void main(String[] args) {
        System.out.println(k);
    }

}

出力は 2 になります。

初期化の順序は次のとおりです。 ..クラスのクラス変数初期化子と静的初期化子...、テキストの順序で、それらが単一のブロックであるかのように。

(コードの) 値は次のとおりです: k = 0 (デフォルト)、次に 2 に設定され、次に 1 に戻されます。

次のコードを実行して、実際に 2 に設定されていることを確認できます。

private static class Test {

    static {
        System.out.println(Test.k);
        k = 2;
        System.out.println(Test.k);
        }
    static int k = 1;

    public static void main(String[] args) {
        System.out.println(k);
    }
}
于 2012-11-25T19:28:53.180 に答える
5

簡潔な答え

クラスの初期化が開始kされると、初期値は 0 になります。

静的ブロック (宣言内の代入より前にあるため) が実行され、k2 が代入されます。

次に、宣言内の初期化子が実行され、k1 が割り当てられます。

長い説明

あなたの例は少し単純なので、この例を使用しましょう。

class TestInitOrder {
  static {
    System.out.println(TestInitOrder.stat1);
    System.out.println(TestInitOrder.stat2);
    System.out.println(TestInitOrder.str);
    System.out.println(TestInitOrder.str2);

    str = "something";

    System.out.println(TestInitOrder.str);
    System.out.println(TestInitOrder.str2);
    System.out.println(TestInitOrder.lazy);
    System.out.println(TestInitOrder.second);
  }

  private static final int stat1 = 10;
  static final String str2 = "sdfff";
  static String str = "crap";
  private static int stat2 = 19;
  static final Second second = new Second();
  static final int lazy;

  static {
    lazy = 20;
  }

  static {
    System.out.println(TestInitOrder.str2);
    System.out.println(TestInitOrder.stat2);
    System.out.println(TestInitOrder.str);
    System.out.println(TestInitOrder.lazy);
    System.out.println(TestInitOrder.second);
  }

  public static void main(String args[]) {
  }

}

class Second {
  public Second() {
    System.out.println(TestInitOrder.second);
  }
}

Java Language Specificationによると、セクション 4.12.5から:

プログラム内のすべての変数は、その値が使用される前に値を持つ必要があります。

  • 各クラス変数、インスタンス変数、または配列コンポーネントは、作成時にデフォルト値で初期化されます

(仕様の次の行は、すべてのタイプのデフォルト値を指定します。基本的には、 、 、 などの 0 の0形式0.0dですnullfalse)

そのため、(これらの理由のいずれかにより) クラスが初期化される前に、変数は初期値を保持します。

詳細な初期化手順によると(ここでは興味深い手順のみを引用し、私のものを強調しています):

6. [...] 次に、値がコンパイル時の定数式であるインターフェイスのfinalクラス変数フィールドを初期化します(§8.3.2.1、§9.3.1、§13.4.9、§15.28)。

[...]

9. 次に、クラスのクラス変数初期化子と静的初期化子、またはインターフェイスのフィールド初期化子を、単一のブロックであるかのようにテキスト順に実行します。

ステップ 6 を見てみましょう。4 つのクラスfinal変数: stat1str2secondlazy

10は定数式であるため、 はで"sdfff"あり、 は実行順序により、 と の初期値を観測することはできませ。観察を行うために、最も早くできるのはステップ 9 です。str2stat1

の場合はsecond、右辺がコンパイル時の定数式ではないため、その初期値が表示されることを示しています。

割り当ては静的ブロックで行われ、ステップ 9 で発生するため、ケースlazyは異なります。したがって、その初期値を観察することができます。(まあ、コンパイラは、lazy一度だけ割り当てられていることを注意深くチェックします)。


コンパイル時の定数式による最終的なクラス変数の初期化の後、静的ブロックと残りの初期化子が実行されます。

例からわかるように、静的ブロックと初期化はテキストの順序に従って行われます (str変数の使用で示されています)。最初にnull、次にsomething、次にcrap.

于 2012-11-25T21:22:39.113 に答える