Java中的静态块未执行

时间:2013-05-31 09:10:27

标签: java static access-modifiers

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访问修饰符导致类没有加载,那么变量如何获取内存?

5 个答案:

答案 0 :(得分:132)

  1. static final int字段是编译时常量,其值被硬编码到目标类中,而不引用其原点;
  2. 因此你的主类不会触发包含该字段的类的加载;
  3. 因此不会执行该类中的静态初始化程序。
  4. 具体细节,编译后的字节码对应于:

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

    一旦删除final,它就不再是编译时常量,并且上述特殊行为不适用。正如您所期望的那样加载Mno类,并执行静态初始化程序。

答案 1 :(得分:8)

未加载课程的原因是VALfinal AND ,初始化为a constant expression(9090)。如果且仅当满足这两个条件时,在编译时评估常量并在需要时“硬编码”。

为防止在编译时计算表达式(并使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; }
    

答案 2 :(得分:5)

如果您使用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        

您可以在“11: sipush 9090”中清楚地看到直接使用静态最终值,因为Mno.VAL是编译时常量。因此,不需要加载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);
    }
}

答案 3 :(得分:1)

1)实际上你还没有扩展那个Mno类,所以当编译开始时它将生成变量VAL的常量,当执行开始时需要该变量来自memory.so它的负载它不需要你的类引用以便静态的bock没有执行。

2)如果A类在那时扩展了Mno类,那么静态块包含在A类中,如果你这样做,则执行该静态块。 例如..  公共类A延伸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);
    }
}

答案 4 :(得分:0)

据我所知,它将按照出现的顺序执行。例如:

 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”类并在另一段代码中“执行”时,静态(=> print)被初始化(我的情况下,我做了“new Statique()”。