16

私は興味深いことに遭遇しました:

static {
    System.out.println(test);     // error cannot reference a field before it is defined
    System.out.println(cheat());  // OK! 
}

private static boolean cheat() {
    return test;
}

private static boolean test = true;

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

最初の方法は間違っており、コンパイラとIDEの両方が間違っていると通知します。2番目のケースでは、不正行為は問題ありませんが、実際にはフィールドはデフォルトでに設定testされていますfalse。SunJDK6を使用します。

4

3 に答える 3

11

これはJLS 8.3.2.3で定義されています。特に:

メンバーの宣言は、C の [...] 静的初期化子で使用される場合 [...] 使用される前にテキストで表示される必要があります。

電話をかけるcheat()ときは、そのルールを回避します。これは、実際には、そのセクションの例のリストの5 番目の例です。

はまだ初期化されていないcheat()ため、静的イニシャライザ ブロックで false を返すことに注意してください。test

于 2013-01-29T16:54:00.670 に答える
3

クラスのロードは次の順序で行われるため:

  • クラス定義 (メソッド、シグネチャ) を読み込みます
  • 静的変数参照 ( 用test) にメモリを割り当てます - まだ初期化されていません
  • staticイニシャライザ (変数用) とstaticブロックを実行します - それらが定義されている順に実行します

つまり、リーチstaticブロックまでに、メソッド定義の準備はできていますが、変数の準備はできていません。あなたcheat()は実際には初期化されていない値を読んでいます。

于 2013-01-29T16:55:56.390 に答える
1

これは、クラスの読み込みが行われる一般的な手順です。

  1. ロード-クラスをメモリにロードします
  2. 検証-クラスeのバイナリ表現が正しいことを確認します
  3. 準備-クラスの静的フィールドを作成し、それらのフィールドを標準のデフォルト値に初期化します。
  4. 初期化-静的フィールドの静的初期化子と初期化子を呼び出します

準備後、テストはfalseになります。次に、静的変数をtrueに割り当てる前に、静的ブロックが実行されます。そのため、falseが発生します。

静的変数をfinalにしてみてください。その場合、trueになります。これは、コンパイラ自体が最適化の一部として(フィールドがfinalであるため)バイトコードに値を埋め込むためです。

于 2013-01-29T17:14:24.280 に答える