web-dev-qa-db-ja.com

Java実行されない静的ブロック

class Test{
    public static void main(String arg[]){    
        System.out.println("**MAIN METHOD");
        System.out.println(Mno.VAL);//SOP(9090);
        System.out.println(Mno.VAL+100);//SOP(9190);
    }

}

class Mno{
    final static int VAL=9090;
    static{
        System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
    }
}

クラスがロードされたときにstaticブロックが実行されることを知っています。ただし、この場合、Mnoブロックが実行されていないため、クラスfinal内のインスタンス変数はstaticです。

どうしてこんなことに? finalを削除する場合、それは正常に動作しますか?

どのメモリが最初に割り当てられるか、static final変数またはstaticブロック?

finalアクセス修飾子によりクラスがロードされない場合、変数はどのようにメモリを取得できますか?

86
Sthita
  1. static final intフィールドはコンパイル時定数であり、その値はそのオリジンへの参照なしで宛先クラスにハードコーディングされています。
  2. したがって、メインクラスはフィールドを含むクラスのロードをトリガーしません。
  3. したがって、そのクラスの静的初期化子は実行されません。

具体的には、コンパイルされたバイトコードはこれに対応します。

public static void main(String arg[]){    
    System.out.println("**MAIN METHOD");
    System.out.println(9090)
    System.out.println(9190)
}

finalを削除するとすぐに、コンパイル時の定数ではなくなり、上記の特別な動作は適用されません。 Mnoクラスは期待どおりにロードされ、その静的初期化子が実行されます。

132
Marko Topolnik

クラスがロードされない理由は、VALfinal[〜#〜] and [〜#〜]定数式 (9090)で初期化されます。これらの2つの条件が満たされた場合にのみ、定数はコンパイル時に評価され、必要に応じて「ハードコーディング」されます。

式がコンパイル時に評価されないようにする(およびJVMにクラスをロードさせる)には、次のいずれかを実行できます。

  • 最終キーワードを削除します。

    static int VAL = 9090; //not a constant variable any more
    
  • または、右辺の式を定数でないものに変更します(変数がまだ最終的な場合でも):

    final static int VAL = getInt(); //not a constant expression any more
    static int getInt() { return 9090; }
    
8
assylias

javap -v Test.classを使用して生成されたバイトコードが表示される場合、main()は次のようになります。

public static void main(Java.lang.String[]) throws Java.lang.Exception;
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field Java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String **MAIN METHOD
         5: invokevirtual #4                  // Method Java/io/PrintStream.println:(Ljava/lang/String;)V
         8: getstatic     #2                  // Field Java/lang/System.out:Ljava/io/PrintStream;
        11: sipush        9090
        14: invokevirtual #5                  // Method Java/io/PrintStream.println:(I)V
        17: getstatic     #2                  // Field Java/lang/System.out:Ljava/io/PrintStream;
        20: sipush        9190
        23: invokevirtual #5                  // Method Java/io/PrintStream.println:(I)V
        26: return        

Mno.VALはコンパイル時定数であるため、「11: sipush 9090」で静的な最終値が直接使用されていることが明確にわかります。したがって、Mnoクラスをロードする必要はありません。したがって、Mnoの静的ブロックは実行されません。

以下のようにMnoを手動でロードすることにより、静的ブロックを実行できます。

class Test{
    public static void main(String arg[]) throws Exception {
        System.out.println("**MAIN METHOD");
        Class.forName("Mno");                 // Load Mno
        System.out.println(Mno.VAL);
        System.out.println(Mno.VAL+100);
    }

}

class Mno{
    final static int VAL=9090;
    static{
        System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
    }
}
5
Xolve

1)実際には、そのMnoクラスを拡張していないため、コンパイル開始時に変数VALの定数が生成され、その変数がメモリからロードされる必要があるときに実行が開始されるため、静的参照が実行されないようにクラス参照は必要ありません。

2)クラスがそのMnoクラスを拡張する場合、その静的ブロックはAクラスに含まれます。これを行うと、その静的ブロックが実行されます。例えば.. public class A extends Mno {

public static void main(String arg[]){    
    System.out.println("**MAIN METHOD");
    System.out.println(Mno.VAL);//SOP(9090);
    System.out.println(Mno.VAL+100);//SOP(9190);
}

}

class Mno{
      final static int VAL=9090;
    static`{`
        System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
    }
}
1
Ketan_Patel

私の知る限り、それは出現順に実行されます。例えば ​​:

 public class Statique {
     public static final String value1 = init1();

     static {
         System.out.println("trace middle");
     }
     public static final String value2 = init2();


     public static String init1() {
         System.out.println("trace init1");
         return "1";
     }
     public static String init2() {
         System.out.println("trace init2");
         return "2";
     }
 }

印刷します

  trace init1
  trace middle
  trace init2

クラス "Statique"が実際に使用され、別のコードで "実行"されると、静的変数が初期化(=>印刷)されます(私の場合は "new Statique()"を実行しました)。

0
Fabyen